Swift中的Array<T>、ContiguousArray<T>和ArraySlice<T>有什么区别?

What’s the difference between Array<T>, ContiguousArray<T>, and ArraySlice<T> in Swift?

在Swift2中,三种数组变体的主要区别是什么:

谁能用真实世界的例子解释一下?

Swift 定义了以下实现 ArrayType 协议的 classes; 数组、连续数组、切片

Swift 数组是表示数组的主要 class,该数组是一个泛型 class,具有 1 种类型,整数数组的类型为 Array<Int>,创建一个整数数组:

var myArray = Array<Int>()

Slice 是一个具有内部实现的数组,它使得从数组顶部移除元素的计算成本更低。以下将在 Slice 类型上表现良好:

var arr = [1,2,3,4,5]
arr[1…4]

关于ContiguousArray的文档不多,但从名字可以猜到它与内部数组存储有关,可能元素存储在Contiguous Memory Allocation布局中。

Read more.

来自docs

连续数组:

Efficiency is equivalent to that of Array, unless T is a class or @objc protocol type, in which case using ContiguousArray may be more efficient. Note, however, that ContiguousArray does not bridge to Objective-C. See Array, with which ContiguousArray shares most properties, for more detail.

基本上,无论何时将 @objc protocol 类型存储在数组中,您可能需要考虑使用 ContiguousArray 而不是 Array.

ArraySlice

ArraySlice always uses contiguous storage and does not bridge to Objective-C.

Warning: Long-term storage of ArraySlice instances is discouraged

Because a ArraySlice presents a view onto the storage of some larger array even after the original array's lifetime ends, storing the slice may prolong the lifetime of elements that are no longer accessible, which can manifest as apparent memory and object leakage. To prevent this effect, use ArraySlice only for transient computation.

当您想从数组中获取子范围时,大多数时候都会使用 ArraySlices,例如:

let numbers = [1, 2, 3, 4]
let slice = numbers[Range<Int>(start: 0, end: 2)] //[1, 2]

您应该使用的任何其他情况 Array

Swift 的不同 class 的良好来源是:http://swiftdoc.org/

数组已经很清楚了,再来说说另外两个。

连续数组:http://swiftdoc.org/type/ContiguousArray/

A fast, contiguously-stored array of T.

Efficiency is equivalent to that of Array, unless T is a class or @objc protocol type, in which case using ContiguousArray may be more efficient. Note, however, that ContiguousArray does not bridge to Objective-C. See Array, with which ContiguousArray shares most properties, for more detail.

数组切片:http://swiftdoc.org/type/ArraySlice/

The Array-like type that represents a sub-sequence of any Array, ContiguousArray, or other ArraySlice.

ArraySlice always uses contiguous storage and does not bridge to Objective-C.

简而言之:

ContiguousArray 用于在 T 为 class 或 @objc 协议类型时提高效率 ArraySlice是表示Array in sub part.

Apple 有新文档。 https://git.io/vg5uw

所以,

ContiguousArray<Element> is the fastest and simplest of the three—use this when you need "C array" performance. The elements of a ContiguousArray are always stored contiguously in memory.

.

Array<Element> is like ContiguousArray<Element>, but optimized for efficient conversions from Cocoa and back—when Element can be a class type, Array<Element> can be backed by the (potentially non-contiguous) storage of an arbitrary NSArray rather than by a Swift ContiguousArray. Array<Element> also supports up- and downcasts between arrays of related class types. When Element is known to be a non-class type, the performance of Array<Element> is identical to that of ContiguousArray<Element>.

切片维护索引

这不是一个完整的答案。但是来自 Swift:

的小 gothcha 的东西
let array = [1,4,9,12,15]

您认为以下值相同吗?

print(array[2..<5].index(of:12)) // is it 1 or 3?
print(array.index(of:12)) // 3

是的!两者都会打印 3。这是因为 ArraySlice 不会获得其自己的唯一副本(除非 Array 发生变异)。 ArraySlice 基本上是一种查看同一数组的某些索引的方法。它不会创建一个新的 [9,12,15] 数组并查看它。它只会查看原始数组的给定范围

现在这个怎么样?您认为以下值相同吗?

print(array[2..<5].index(of:1)) // nil
print(array.index(of:1)) // 0

没有! ArraySlice 将打印 nil,而 Array 将打印 0

显然:

print(array[2..<4][2]) // 9
print(array[2..<4][0]) // ERROR: out of bounds

再次令人惊讶:

print(array.dropFirst(2).index(of:15) 

不是2。它会 return 4 作为它的索引。为什么?因为 dropFirst return 是一个 ArraySlice。如果您不希望它维护索引,那么您应该从 ArraySlice 构造一个新的 Array...

编辑:

来自 docs:

Unlike Array and ContiguousArray, the starting index for an ArraySlice instance isn’t always zero. Slices maintain the same indices of the larger array for the same elements, so the starting index of a slice depends on how it was created, letting you perform index-based operations on either a full array or a slice.

如果您有兴趣了解更多。文档的 link 还有另一个例子