我已经阅读过多篇文章和文章,了解ArraySlice
如何在“Swift”中使用Array
。
但是,我无法找到的内部工作原理是什么? ArraySlice是阵列上的视图究竟意味着什么?
var arr = [1, 2, 3, 4, 5]
let slice = arr[2...4]
arr.remove(at: 2)
print(slice.startIndex) //2
print(slice.endIndex) //5
slice[slice.startIndex] //3
在上面的代码中,我已从index-2 (i.e 3)
移除arr
处的元素。
Index-2
也是startIndex
的{{1}}。
当我打印slice
时,它仍会打印3。
由于没有为slice[slice.startIndex]
创建额外的存储空间,那么ArraySlice
中的任何更改如何反映在Array
中?
文章/帖子可以在这里找到:
答案 0 :(得分:2)
Array
和ArraySlice
都是值类型,表示在
var array = [0, 1, 2, 3, 4, 5]
var slice = array[0..<2]
array
和slice
是独立的值,而变异的值不会影响另一个:
print(slice) // [0, 1]
array.remove(at: 0)
print(slice) // [0, 1]
如何实现Swift标准库的实现细节,
但是可以检查源代码以获得一些想法:At
Array.swift#L1241
我们找到了Array.remove(at:)
:
public mutating func remove(at index: Int) -> Element {
_precondition(index < endIndex, "Index out of range")
_precondition(index >= startIndex, "Index out of range")
_makeUniqueAndReserveCapacityIfNotUnique()
// ...
}
使用
@inlinable
@_semantics("array.make_mutable")
internal mutating func _makeUniqueAndReserveCapacityIfNotUnique() {
if _slowPath(!_buffer.isMutableAndUniquelyReferenced()) {
_copyToNewBuffer(oldCount: _buffer.count)
}
}
遵循该追踪,我们在ArrayBuffer.swift#L107
找到 /// Returns `true` iff this buffer's storage is uniquely-referenced.
@inlinable
internal mutating func isUniquelyReferenced() -> Bool {
// ...
}
这还不是完整的实现,但(希望)已经证明了这一点
(变异)remove(at:)
方法将元素存储复制到新的
缓冲区if是共享的(与另一个数组或数组切片)。
我们还可以通过打印元素存储基地址来验证:
var array = [0, 1, 2, 3, 4, 5]
var slice = array[0..<2]
array.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000101927190
slice.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000101927190
array.remove(at: 0)
array.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000101b05350
slice.withUnsafeBytes { print($0.baseAddress!) } // 0x0000000101927190
如果是数组,字典或字符串,则使用相同的“写时复制”技术
已复制,或String
和Substring
共享存储空间。
因此,数组切片与其原始内容共享元素存储 数组只要它们都没有变异。
这仍然是一个有用的功能。这是一个简单的例子:
let array = [1, 4, 2]
let diffs = zip(array, array[1...]).map(-)
print(diffs) // [-3, 2]
array[1...]
是给定数组的视图/切片,没有实际复制
要素。
递归二进制搜索函数,其中向下传递切片(左半部分或右半部分)将是另一个应用程序。
答案 1 :(得分:1)
数组切片是底层数组的视图并保留数组。
可能(不是100%肯定),当你从数组中删除一个元素时,它仍然被保留,并且只是被标记为已删除。
这就是为什么当您打印数组时,您看不到3
,但切片仍然显示它。
class Car : CustomStringConvertible {
var description: String {
let objectIdentifier = ObjectIdentifier(self) //To get the memory address
return "car instance - \(objectIdentifier) "
}
deinit {
print("car deallocated")
}
}
var carSlice : ArraySlice<Car>?
var cars : [Car]? = [Car(), Car(), Car()]
carSlice = cars?[0...1]
print("Going to make cars nil")
cars = nil
print("cars = \(cars?.description ?? "nil")")
print("carSlice = \(carSlice?.description ?? "nil")")
print("----------------")
print("Going to make carSlice nil")
carSlice = nil
print("carSlice = \(carSlice?.description ?? "nil")")
Going to make cars nil
cars = nil
carSlice = [car instance - ObjectIdentifier(0x000060c00001e7b0) , car instance - ObjectIdentifier(0x000060c00001e7c0) ]
----------------
Going to make carSlice nil
carSlice = nil
car deallocated
car deallocated
car deallocated
不鼓励长期存储ArraySlice实例。一片 拥有对更大阵列的整个存储的引用,而不仅仅是 即使在原始阵列的生命周期之后,也会显示它所呈现的部分 结束。因此,长期存储切片可延长寿命 可以出现的不再可访问的元素 是记忆和物体泄漏。