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

Would mutating an ArraySlice instantiate a new array instance?

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 的引述:

Neither the firstHalf nor secondHalf slices allocate any new storage of their own. Instead, each presents a view onto the storage of the absences array.

当我尝试按如下方式改变 firstHalf 时:

firstHalf[1] = 19

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

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

在您的情况下,切片 firstHalf 对其具有视图的底层数组缓冲区是非唯一引用的(因为 absencessecondHalf 也对其具有视图).因此,当你去改变 firstHalf 时,一个副本被触发——创建一个包含切片元素的 new 缓冲区(但不一定是 entire数组)。

firstHalf 现在对这个新缓冲区有独特的看法,absencessecondHalf 都共享对旧数组缓冲区的看法。因此 firstHalf 现在可以在不影响原始数组元素的情况下改变其缓冲区的元素,从而保留值语义。

这是 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.