如何在 Swift 中的字符串类型上证明 "copy-on-write"
How to prove "copy-on-write" on String type in Swift
正如标题所说,我试图证明自己 Swift 中的 String 支持 COW(copy on write)。但我找不到证据。在尝试以下代码后,我在 Array 和 Dictionary 上证明了 COW:
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var xArray = [20, 30, 40, 50, 60]
var yArray = xArray
// These two addresses were the same
address(of: xArray)
address(of: yArray)
yArray[0] = 200
// The address of yArray got changed
address(of: yArray)
但是对于 String 类型,它不起作用。
var xString = "Hello World"
var yString = xString
// These two addresses were different
address(of: xString)
address(of: yString)
我从官方 Swift 代码库中转储了测试函数。
func _rawIdentifier(s: String) -> (UInt, UInt) {
let tripe = unsafeBitCast(s, to: (UInt, UInt, UInt).self)
let minusCount = (tripe.0, tripe.2)
return minusCount
}
但是这个函数似乎只转换指向的实际值而不是地址。因此,两个具有相同值的不同字符串变量将具有相同的 rawIdentifier。仍然无法向我证明 COW。
var xString = "Hello World"
var yString = "Hello" + " World"
// These two rawIdentifiers were the same
_rawIdentifier(s: xString)
_rawIdentifier(s: yString)
那么 COW 如何处理 Swift 中的字符串类型?
编译器只为两者创建一个存储
"Hello World"
和 "Hello" + " World"
。
您可以通过检查汇编代码来验证这一点
获得自
swiftc -emit-assembly cow.swift
它只定义了一个字符串文字
.section __TEXT,__cstring,cstring_literals
L___unnamed_1:
.asciz "Hello World"
字符串一旦发生变异,字符串存储的地址
缓冲区(那个 "magic" 元组的第一个成员,实际上是 _baseAddress
struct _StringCore
,在 StringCore.swift 中定义)更改:
var xString = "Hello World"
var yString = "Hello" + " World"
print(_rawIdentifier(s: xString)) // (4300325536, 0)
print(_rawIdentifier(s: yString)) // (4300325536, 0)
yString.append("!")
print(_rawIdentifier(s: yString)) // (4322384560, 4322384528)
为什么你的
func address(of object: UnsafeRawPointer) -> String
函数显示 xArray
和 yArray
的相同值,但是
不适用于 xString
和 yString
?
将 array 传递给采用不安全指针的函数传递
第一个数组元素的地址,两者都相同
阵列,如果他们共享存储。
传递一个字符串给一个接受不安全指针的函数传递一个
指向字符串的临时 UTF-8 表示形式的指针。
该地址在每次调用中可以不同,即使对于相同的字符串也是如此。
此行为记录在“使用 Swift 与 Cocoa 和
Objective-C" UnsafePointer<T>
参数的参考,但显然
对于 UnsafeRawPointer
个参数同样有效。
正如标题所说,我试图证明自己 Swift 中的 String 支持 COW(copy on write)。但我找不到证据。在尝试以下代码后,我在 Array 和 Dictionary 上证明了 COW:
func address(of object: UnsafeRawPointer) -> String {
let addr = Int(bitPattern: object)
return String(format: "%p", addr)
}
var xArray = [20, 30, 40, 50, 60]
var yArray = xArray
// These two addresses were the same
address(of: xArray)
address(of: yArray)
yArray[0] = 200
// The address of yArray got changed
address(of: yArray)
但是对于 String 类型,它不起作用。
var xString = "Hello World"
var yString = xString
// These two addresses were different
address(of: xString)
address(of: yString)
我从官方 Swift 代码库中转储了测试函数。
func _rawIdentifier(s: String) -> (UInt, UInt) {
let tripe = unsafeBitCast(s, to: (UInt, UInt, UInt).self)
let minusCount = (tripe.0, tripe.2)
return minusCount
}
但是这个函数似乎只转换指向的实际值而不是地址。因此,两个具有相同值的不同字符串变量将具有相同的 rawIdentifier。仍然无法向我证明 COW。
var xString = "Hello World"
var yString = "Hello" + " World"
// These two rawIdentifiers were the same
_rawIdentifier(s: xString)
_rawIdentifier(s: yString)
那么 COW 如何处理 Swift 中的字符串类型?
编译器只为两者创建一个存储
"Hello World"
和 "Hello" + " World"
。
您可以通过检查汇编代码来验证这一点 获得自
swiftc -emit-assembly cow.swift
它只定义了一个字符串文字
.section __TEXT,__cstring,cstring_literals L___unnamed_1: .asciz "Hello World"
字符串一旦发生变异,字符串存储的地址
缓冲区(那个 "magic" 元组的第一个成员,实际上是 _baseAddress
struct _StringCore
,在 StringCore.swift 中定义)更改:
var xString = "Hello World"
var yString = "Hello" + " World"
print(_rawIdentifier(s: xString)) // (4300325536, 0)
print(_rawIdentifier(s: yString)) // (4300325536, 0)
yString.append("!")
print(_rawIdentifier(s: yString)) // (4322384560, 4322384528)
为什么你的
func address(of object: UnsafeRawPointer) -> String
函数显示 xArray
和 yArray
的相同值,但是
不适用于 xString
和 yString
?
将 array 传递给采用不安全指针的函数传递 第一个数组元素的地址,两者都相同 阵列,如果他们共享存储。
传递一个字符串给一个接受不安全指针的函数传递一个 指向字符串的临时 UTF-8 表示形式的指针。 该地址在每次调用中可以不同,即使对于相同的字符串也是如此。
此行为记录在“使用 Swift 与 Cocoa 和
Objective-C" UnsafePointer<T>
参数的参考,但显然
对于 UnsafeRawPointer
个参数同样有效。