Swift 序列()上的compactMap不懒惰?
每隔一段时间,我必须沿着响应者链走一段路,才能到达一个已知类的实例。(为了回答这个问题,请接受这一点。)我一直在用while循环来做这件事,但我突然想到,使用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 {
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 {
...
}
我加了一条评论,我相信这是相关的。