Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 序列()上的compactMap不懒惰?_Swift_Lazy Sequences - Fatal编程技术网

Swift 序列()上的compactMap不懒惰?

Swift 序列()上的compactMap不懒惰?,swift,lazy-sequences,Swift,Lazy Sequences,每隔一段时间,我必须沿着响应者链走一段路,才能到达一个已知类的实例。(为了回答这个问题,请接受这一点。)我一直在用while循环来做这件事,但我突然想到,使用sequence(),它可以像这样简洁地表达响应者链本身会更酷: let chain = sequence(first: someView as UIResponder) {$0.next} if let vc = (chain.first {$0 is ViewController}) as? ViewController {

每隔一段时间,我必须沿着响应者链走一段路,才能到达一个已知类的实例。(为了回答这个问题,请接受这一点。)我一直在用while循环来做这件事,但我突然想到,使用
sequence()
,它可以像这样简洁地表达响应者链本身会更酷:

let chain = sequence(first: someView as UIResponder) {$0.next}
if let vc = (chain.first {$0 is ViewController}) as? ViewController {
    print(vc)
}
这太棒了,因为到目前为止,我们还没有真正做过任何步行;序列是惰性的,在我们开始请求元素之前,匿名函数不会执行。为了证明这一点,让我用打印语句插入该代码:

let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}
好的,假设我正在寻找链中的第一个ViewController实例。我可以这样找到它:

let chain = sequence(first: someView as UIResponder) {$0.next}
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)
}

它的工作原理是编译并得到正确的答案,看起来不错,但我已经失去了懒惰。正在遍历整个
链。
compactMap
是否会失去惰性?有办法把它拿回来吗?(或者有没有其他优雅的方式完全让我不知所措?

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

  • 如果希望序列延迟调用
    compactMap
    ,则需要使用

  • 看来,
    首先
    是在阻止懒惰行为。但是,如果您首先使用
    (其中:)
    ,您确实喜欢这种懒惰行为

  • 因此,虽然有点不雅观,但以下内容实现了您的期望:

    if let vc = (chain.lazy.compactMap { $0 as? ViewController }.first { _ in true } ) {
        ...
    } 
    
    或者,正如您所说,您可以在
    序列上实现
    first
    (或
    lazyFirst
    ):

    extension Sequence {
        var first: Element? {
            return first { _ in true }
        }
    }
    
    现在这个更简化的格式副本仍然是懒惰的:

    if let vc = chain.lazy.compactMap({ $0 as? ViewController }).first {
        ...
    } 
    
    我加了一条评论,我相信这是相关的。