下标惰性过滤器如何工作?
let ary = [0,1,2,3]
let empty = ary.lazy.filter { $0 > 4 }.map { $0 + 1 }
print(Array(empty)) // []
print(empty[2]) // 3
看起来它只是忽略了过滤器并且仍然执行了映射。这在某处有记录吗?还有哪些惰性集合具有这样的异常行为?
答案 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
是可以用整数索引的集合,使用绝对整数访问该集合的元素仍然不安全,因为该集合可能具有一组不同的索引。