为什么Swift标准库中的reverse()函数返回ReverseRandomAccessCollection?

时间:2016-01-01 17:35:31

标签: arrays swift standard-library

现在我已经学会了Swift(达到一个合理的水平)我正试图掌握标准库,但事实上它主要是ελληνικά给我!

所以一个特定的问题:我有一个字符串数组,我可以在其上调用reverse()。

let arr = ["Mykonos", "Rhodes", "Naxos"].reverse()

现在天真地我以为我会从中找回一种类型的数据。 (例如Ruby有一个类似的方法,你传递一个数组并返回一个数组)

但是arr现在实际上是

类型
ReverseRandomAccessCollection<Array<String>>

实际上是一个符合CollectionType的结构:

public struct ReverseRandomAccessCollection<Base : CollectionType where Base.Index : RandomAccessIndexType> : _ReverseCollectionType

这意味着我可以这样做:

for item in arr {
  print(item)
}

但我做不到

print(arr[0])

为什么设计成这种方式?

Swift中的字典也实现了CollectionType,所以我可以这样做:

let dict = ["greek" : "swift sometimes", "notgreek" : "ruby for this example"].reverse()

但字典不像数组那样排序,为什么我可以在dicts上调用reverse()?

奖励积分如果有人能指出我可以阅读的方向并改善我的Swift stdlib foo,Ευχαριστώ!

3 个答案:

答案 0 :(得分:27)

这是时间和内存的性能优化。 ReverseRandomAccessCollection表示了元素 原始数组的顺序相反,无需创建新数组 并复制所有元素(只要原始数组不是 突变)。

可以使用下标访问反向元素:

let el0 = arr[arr.startIndex]
let el2 = arr[arr.startIndex.advancedBy(2)]

for i in arr.indices {
    print(arr[i])
}

您还可以使用

显式创建数组
let reversed = Array(["Mykonos", "Rhodes", "Naxos"].reversed())

词典也是键/值对的序列。在

let dict = ["greek" : "swift sometimes", "notgreek" : "ruby for this example"].reverse()

调用完全不同的reversed()方法:

extension SequenceType {
    /// Return an `Array` containing the elements of `self` in reverse
    /// order.
    ///
    /// Complexity: O(N), where N is the length of `self`.
    @warn_unused_result
    public func reversed() -> [Self.Generator.Element]
}

结果是一个包含字典键/值对的数组 以相反的顺序。但这是有限的使用,因为订单 字典中的键/值对可以是任意的。

答案 1 :(得分:3)

来自language docs of ReverseCollention.reverse()的结果):

  

当应用于具有的集合时,reverse()方法始终是惰性的   双向指数,但不暗示赋予懒惰   算法应用于其结果。

     

换句话说,对于具有双向索引的普通集合c:

     
      
  • c.reverse()执行不创建新存储空间
  •   
     

...

因此,您可以将ReverseRandomAccessCollection视为尚未反转的数组的随机访问包装(即原始数组arr尚未被复制和撤消到记忆中的新位置。)

当然,从上面开始,你不能直接索引反向集合,因为Array提供访问作为指向保存数组的内存的指针,索引对应于按位进行(取决于类型)在记忆中前进。但是,我们仍然可以使用ReverseRandomAccessIndex访问数组索引样式中的“反向数组”元素:

let arr = ["Mykonos", "Rhodes", "Naxos"]
let arrReverse = arr.reverse()
    /* ReverseRandomAccessCollection access "wrapper" over
       the 'arr' data in memory. No new storage allocated */

let myIndex = arrReverse.startIndex.advancedBy(2)
    /* bIndex type: 
       ReverseRandomAccessIndex<ReverseRandomAccessIndex<Index>> */

print(arrReverse[myIndex]) // "Mykonos"

相反,我们可以为反向数组显式分配内存,并将其视为任何其他数组。此时,arrReverse是一个独立的数组,而不是arr,除了(一次)使用它之外与前者无关。

let arr = ["Mykonos", "Rhodes", "Naxos"]
let arrReverse = Array(arr.reverse())
    /* Array<String> */

let myIndex = arrReverse.startIndex.advancedBy(2)
    /* bIndex type: Int */

print(arrReverse[myIndex]) // "Mykonos"

Martin R打败了我,所以请看他关于词典的说明。

答案 2 :(得分:1)

使用Swift 3.0,您可以通过索引直接访问Array值。

var streets = ["Albemarle", "Brandywine", "Chesapeake"]
streets = streets.reversed()
print("Array at index is \(streets[0])")

这将打印“切萨皮克”