今天我们通过查看内存、汇编以及 Swift
源码等多途径来探究一下 Swift
中的 String
的内存布局及底层实现。
空字符串
首先创建一个最简单的字符串,空字符串str1
:
从图中可以看到,String
内部有个 _StringGuts
,_StringGuts
内部有个 _StringObject
,_StringObject
内部有个 Builtin.BridgeObject
类型的_object
和一个 UInt64
类型的 _countAndFlagsBits
。
找到 StringGuts 源码,可以看到 _StringGuts
是一个结构体,里面有个 _StringObject
类型的成员 _object
,跟上面 Xcode
打印的一致。
搜索关键词 empty
,可以轻松找到创建空字符串的初始化方法:调用 _StringObject
的方法empty:() 生成一个空的 _StringObject
对象后传入到自身默认初始化方法:init(_ object: _StringObject) 中。
进一步查看 StringObject 源码,同样搜索关键词 empty
,找到方法:init(empty:())。因为我们的设备是64位,所以这个方法会进入到第一个分支中,分别初始化成员:_countAndFlagsBits
和 _object
(也跟图一的打印保持一致)。
Nibbles
是个枚举,源码中给它加了多个extension
。进一步查看源码可以看到 Nibbles.emptyString
,调用方法:small(isASCII: Bool)
enum Nibbles {}
extension _StringObject.Nibbles {
// The canonical empty string is an empty small string
@inlinable @inline(__always)
internal static var emptyString: UInt64 {
return _StringObject.Nibbles.small(isASCII: true)
}
}
extension _StringObject.Nibbles {
// Discriminator for small strings
@inli