即以 Unicode Scarlar
的方式来查看字符串。
/// let flag = "??"
/// for v in flag.unicodeScalars {
/// print(v.value)
/// }
/// // 127477
/// // 127479
UnicodeScalarView
是一个结构体
extension String {
@_fixed_layout
public struct UnicodeScalarView {
@usableFromInline
internal var _guts: _StringGuts
@inlinable @inline(__always)
internal init(_ _guts: _StringGuts) {
self._guts = _guts
_invariantCheck()
}
}
}
只有一个变量,类型是_StringGuts
。
UnicodeScalarView
遵守 BidirectionalCollection
协议
所以可以正向/反向遍历。核心代码如下:
@inlinable @inline(__always)
public func index(before i: Index) -> Index {
precondition(i.encodedOffset > 0)
// TODO(String performance): isASCII fast-path
if _fastPath(_guts.isFastUTF8) {
let len = _guts.withFastUTF8 { utf8 -> Int in
return _utf8ScalarLength(utf8, endingAt: i.encodedOffset)
}
_internalInvariant(len <= 4, "invalid UTF8")
return i.encoded(offsetBy: -len)
}
return _foreignIndex(before: i)
}
internal func _foreignIndex(before i: Index) -> Index {
_internalInvariant(_guts.isForeign)
let priorIdx = i.priorEncoded
let cu = _guts.foreignErrorCorrectedUTF16CodeUnit(at: priorIdx)
let len = _isTrailingSurrogate(cu) ? 2 : 1
return i.encoded(offsetBy: -len)
}
在String
里读写 unicodeScalars
@inlinable
public var unicodeScalars: UnicodeScalarView {
@inline(__always) get { return UnicodeScalarView(_guts) }
@inline(__always) set { _guts = newValue._guts }
}
每次读,都会生成一个新的UnicodeScalarView
。
每次写,都会更新String
内部的_guts
。