变异ArraySlice会实例化一个新的数组实例吗?

时间:2017-04-24 13:35:26

标签: arrays swift copy-on-write

var absences = [0, 2, 0, 4, 0, 3, 1, 0]
let midpoint = absences.count / 2

var firstHalf = absences.prefix(upTo: midpoint)
let secondHalf = absences.suffix(from: midpoint)

Apple的报价:

  

firstHalf和secondHalf切片都不会分配任何自己的新存储空间。相反,每个都提供了缺席数组存储的视图。

当我尝试变异firstHalf如下:

firstHalf[1] = 19

firstHalf的值发生了变化,但原始数组absences保持不变(firstHalf[1]等于19而absences[1]等于2) 那么后台会发生什么。我是否通过改变数组切片来实例化一个新数组? 提前谢谢。

2 个答案:

答案 0 :(得分:6)

是的,标准库的集合类型(包括ArrayArraySlice)都具有写时复制行为。这意味着他们可以共享元素与其他集合的存储,直到它们发生变异,在这种情况下,他们会自己复制它们。

在您的情况下,切片firstHalf具有视图的基础数组缓冲区是非唯一引用的(因为absencessecondHalf都有一个视图) 。因此,当您进行变异firstHalf时,会触发一个副本 - 创建一个包含切片元素的 new 缓冲区(但不一定是整个数组)。

firstHalf现在可以使用absences& secondHalf都在旧数组缓冲区上共享视图。因此firstHalf现在可以改变其缓冲区的元素而不影响原始数组的元素,从而保留了值语义。

答案 1 :(得分:4)

这是Swift集合在幕后使用的标准写时复制行为,在您尝试变异之前,它不会复制集合。有关写时复制的讨论,请参阅WWDC 2015视频Building Better Apps with Value Types in Swift

评论in the code为我们澄清了这一点:

/// Slices Share Indices
/// --------------------
///
/// A collection and its slices share the same indices. An element of a
/// collection is located under the same index in a slice as in the base
/// collection, as long as neither the collection nor the slice has been
/// mutated since the slice was created.

...

/// Slices Inherit Collection Semantics
/// -----------------------------------
///
/// A slice inherits the value or reference semantics of its base collection.
/// That is, when working with a slice of a mutable
/// collection that has value semantics, such as an array, mutating the
/// original collection triggers a copy of that collection, and does not
/// affect the contents of the slice.