【问题标题】:Swift lazy subscript ignores filterSwift 惰性下标忽略过滤器
【发布时间】:2019-01-21 16:53:26
【问题描述】:

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

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

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

【问题讨论】:

    标签: swift lazy-evaluation


    【解决方案1】:

    它归结为用一个整数为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 的正确方法是使用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)
    

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

    致命错误:索引超出范围

    【讨论】:

      【解决方案2】:

      要添加到 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 是一个可按整数索引的集合,使用绝对整数访问该集合的元素仍然不安全,因为该集合可能具有不同的索引集。

      【讨论】:

      • 这是有道理的,但这让我想知道为什么他们没有走字符串的路线并完全禁止 int 下标。
      • @Max,可能是为了便于访问,并在尝试从数组中随机访问元素时避免尴尬的构造。几乎所有语言都允许通过整数进行数组索引。
      猜你喜欢
      • 1970-01-01
      • 2018-07-25
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-04
      相关资源
      最近更新 更多