Search code examples
swiftstringfoundation

Swift: String starts(with:) vs hasPrefix


String.hasPrefix (or [NSString hasPrefix]) was always part of Foundation. However, I just noticed that now we also have starts(with:).

This method comes from Sequence but it also works for String.

My question is, which one should I prefer? Are there any performance considerations? I'm used to hasPrefix from Objective-C days, but starts(with:) is more intuitive and works for other sequences.


Solution

  • String.hasPrefix() is implemented in StringLegacy.swift as

    extension String {
    
      public func hasPrefix(_ prefix: String) -> Bool {
        if _fastPath(self._guts.isNFCFastUTF8 && prefix._guts.isNFCFastUTF8) {
          guard prefix._guts.count <= self._guts.count else { return false }
          return prefix._guts.withFastUTF8 { nfcPrefix in
            let prefixEnd = nfcPrefix.count
            return self._guts.withFastUTF8(range: 0..<prefixEnd) { nfcSlicedSelf in
              return _binaryCompare(nfcSlicedSelf, nfcPrefix) == 0
            }
          }
        }
    
        return starts(with: prefix)
      }
    
    }
    

    which means (if I understand it correctly): If both the string and the prefix candidate use a UTF-8 based storage then the UTF-8 bytes are compared directly. Otherwise it falls back to starts(with:) and does a Character based comparison.

    So there is no difference in the result, but hasPrefix() is optimized for native Swift strings.

    Note: This is the from the master (Swift 5) branch, the situation might be different in earlier versions.