Swift 使用 var 时是否有二次字符串连接?

Does Swift have quadratic string concatenation when using var?

In the Swift Language Reference, under String Mutability 它说:

You indicate whether a particular String can be modified (or mutated) by assigning it to a variable (in which case it can be modified), or to a constant (in which case it cannot be modified)

我不清楚可变的"it"是变量还是

例如,如果我写:

var s = ""
for i in 0...100 {
  s += "a"
}

是否类似于创建一个 NSMutableString 并调用 appendString 100 次(即线性成本)?

或者它类似于创建一系列更大的 NSString 实例并将它们与 stringByAppendingString 组合(即二次成本)?

或者它可能在幕后创建了某种绳索结构,所以它是不可变的并且 总体上是线性的?

像这样附加到一个集合(虽然 String 本身不是一个集合,但您实际上是用该代码附加到它的 characters 视图)是线性的,而不是二次的。 Swift 中的字符串有一个内部缓冲区,每当它填满时,其大小就会加倍,这意味着当你重复追加时,你会看到越来越少的重新分配。文档将以这种方式追加描述为 "amortized" O(1) 操作:大部分时间追加是 O(1),但偶尔需要重新分配字符串的存储。

数组、集合和字典具有相同的行为,但如果您知道要追加多次,也可以为数组保留特定容量(使用 reserveCapacity(_:))。


所有这些集合都使用 "copy-on-write" 来保证值语义。这里,xy共享一个缓冲区:

let x = "a"
let y = x

如果你改变 x,它会得到一个新的、唯一的缓冲区副本:

x += "b"
// x == "ab"
// y == "a"

在那之后,x 有自己的缓冲区,因此后续的突变将不需要副本。

x += "c"   // no copy unless buffer is full