Swift中的ArraySlice如何在内部工作?

时间:2018-06-14 07:03:51

标签: arrays swift

我已经阅读过多篇文章和文章,了解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中?

文章/帖子可以在这里找到:

https://dzone.com/articles/arrayslice-in-swift

https://marcosantadev.com/arrayslice-in-swift/

2 个答案:

答案 0 :(得分:2)

ArrayArraySlice都是值类型,表示在

之后
var array = [0, 1, 2, 3, 4, 5]
var slice = array[0..<2]

arrayslice是独立的值,而变异的值不会影响另一个:

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

如果是数组,字典或字符串,则使用相同的“写时复制”技术 已复制,或StringSubstring共享存储空间。

因此,数组切片与其原始内容共享元素存储 数组只要它们都没有变异。

这仍然是一个有用的功能。这是一个简单的例子:

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

Apple文档:

  

不鼓励长期存储ArraySlice实例。一片   拥有对更大阵列的整个存储的引用,而不仅仅是   即使在原始阵列的生命周期之后,也会显示它所呈现的部分   结束。因此,长期存储切片可延长寿命   可以出现的不再可访问的元素   是记忆和物体泄漏。

参见:

https://developer.apple.com/documentation/swift/arrayslice