Swift懒惰下标忽略过滤器

时间:2019-01-21 16:53:27

标签: swift lazy-evaluation

下标惰性过滤器如何工作?

let ary = [0,1,2,3]
let empty = ary.lazy.filter { $0 > 4 }.map { $0 + 1 }
print(Array(empty)) // []
print(empty[2])     // 3

看起来它只是忽略了过滤器并且仍然执行了映射。这在某处有记录吗?还有哪些惰性集合具有这样的异常行为?

2 个答案:

答案 0 :(得分:4)

这归结为用整数下标LazyFilterCollection,在这种情况下,该整数将忽略谓词并将下标操作转发给基数。

例如,如果我们要在数组中寻找严格的正整数:

let array = [-10, 10, 20, 30]
let lazyFilter = array.lazy.filter { $0 > 0 }

print(lazyFilter[3])                 // 30

或者,如果我们要在字符串中寻找小写字母:

let str = "Hello"
let lazyFilter = str.lazy.filter { $0 > "Z" }

print(lazyFilter[str.startIndex])    //H

在两种情况下,下标都转发到基本集合。

LazyFilterCollection下标的正确方法是使用documentation中所述的LazyFilterCollection<Base>.Index

let start = lazyFilter.startIndex
let index = lazyFilter.index(start, offsetBy: 1)
print(lazyFilter[index])  

对于数组示例,它产生20,对于字符串示例,它产生l


以您为例,尝试访问索引3

let start = empty.startIndex
let index = empty.index(start, offsetBy: 3)
print(empty)

会引起预期的运行时错误:

  

致命错误:索引超出范围

答案 1 :(得分:1)

要添加到Carpsen90的答案中,您会遇到Collection的一种特殊情况:不建议也不建议通过绝对索引安全地访问集合,即使类型系统允许这样做也是如此。因为您收到的收藏夹可能是另一个收藏夹的子集。

让我们举一个简单的例子,数组切片:

let array = [0, 1, 2, 3, 4]
let slice = array[2..<3]
print(slice) // [2]
print(slice.first) // Optional(2)
print(slice[0]) // crashes with array index out of bounds

即使slice是可以用整数索引的集合,使用绝对整数访问该集合的元素仍然不安全,因为该集合可能具有一组不同的索引。