【问题标题】:compactMap on sequence() not lazy?sequence() 上的 compactMap 不懒惰?
【发布时间】:2019-06-26 23:31:00
【问题描述】:

每隔一段时间,我必须沿着响应者链向上走,才能到达一个已知类的实例。 (出于问题的目的接受这个。)我一直在用一个while循环来做这个,但我想到使用sequence()会更酷,它可以像这样整齐地表达响应者链本身:

let chain = sequence(first: someView as UIResponder) {$0.next}

这太棒了,因为到目前为止我们还没有真正步行过;该序列是惰性的,并且在我们开始请求元素之前不会执行匿名函数。为了证明这一点,让我用 print 语句检测该代码:

let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}

好的,假设我正在寻找链中的第一个 ViewController 实例。我可以这样找到它:

if let vc = (chain.first {$0 is ViewController}) as? ViewController {
    print(vc)
}

打印输出显示惰性得到了维持:我们沿着响应者链前进,直到到达 ViewController 并停止。完美的!在花括号内,vc 被键入为 ViewController,我们开始比赛了。

不过,它不会逃过你的注意,那是丑陋的。我正在测试和铸造。有没有一种方法可以让我在没有测试的情况下直接投射并最终得到一个 ViewController?

这很优雅,而且效果很好:

for case let vc as ViewController in chain {
    print(vc)
    break
}

这很可爱,而且保持了懒惰——但我必须记得在最后说break,这会毁了一切。

好的,所以当我想到这个时,我真的充满希望:

if let vc = (chain.compactMap{ $0 as? ViewController }.first) {
    print(vc)
}

从某种意义上说,它可以编译并获得正确的答案并且看起来不错,但是我已经失去了懒惰。整个chain 正在被遍历。 compactMap 会不会失去懒惰?有没有办法把它找回来? (或者有什么其他优雅的方式让我完全忘记了?)

【问题讨论】:

    标签: swift lazy-sequences


    【解决方案1】:

    问题本身不是compactMap。有两个问题:

    1. 如果你想让序列懒惰地调用compactMap,你需要使用lazy

    2. first 似乎正在阻止惰性行为。不过,如果您使用first(where:),您确实喜欢这种懒惰的行为。

    因此,虽然有些不雅,但以下实现了您正在寻找的内容:

    if let vc = (chain.lazy.compactMap { $0 as? ViewController }.first { _ in true } ) {
        ...
    } 
    

    或者,如您所说,您可以在Sequence 上实现first(或lazyFirst):

    extension Sequence {
        var first: Element? {
            return first { _ in true }
        }
    }
    

    然后这个更简化的演绎现在仍然是懒惰的:

    if let vc = chain.lazy.compactMap({ $0 as? ViewController }).first {
        ...
    } 
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2012-11-04
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    相关资源
    最近更新 更多