Swift 惰性下标忽略过滤器

Swift lazy subscript ignores filter

订阅延迟过滤器如何工作?

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

看起来它只是忽略了过滤器并无论如何都做了地图。这在某处记录了吗?还有哪些惰性集合有这样的异常行为?

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

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

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

print(lazyFilter[3])                 // 30

或者,如果我们要查找字符串中的小写字符:

let str = "Hello"
let lazyFilter = str.lazy.filter { [=11=] > "Z" }

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

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

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

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)

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

Fatal error: Index out of range

为了补充 Carpsen90 的回答,您 运行 进入了 Collection 的一个特殊性:不推荐,也不安全地通过绝对索引访问 collections,即使类型系统允许这样做。因为您收到的 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 是一个可由整数索引的 collection,使用绝对整数访问 collection 的元素仍然是不安全的,因为 collection 可能有一组不同的指数。