sequence() 上的 compactMap 不懒惰?
compactMap on sequence() not lazy?
每隔一段时间,我必须沿着响应链向上走,才能到达已知 class 的实例。 (只是为了问题的目的接受这个。)我一直在用一个 while 循环来做这个,但我想到使用 sequence()
会更酷,它可以像这样整齐地表达响应者链本身:
let chain = sequence(first: someView as UIResponder) {[=10=].next}
这太棒了,因为到目前为止我们还没有真正走过任何路;该序列是惰性的,直到我们开始请求元素时才会执行匿名函数。为了证明这一点,让我用打印语句检测该代码:
let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}
好的,假设我正在寻找链中的第一个 ViewController 实例。我可以这样找到它:
if let vc = (chain.first {[=12=] 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{ [=14=] as? ViewController }.first) {
print(vc)
}
它的工作原理是它编译并得到正确的答案并且看起来不错,但我已经 失去了懒惰 。正在遍历整个chain
。 compactMap
是否失去懒惰?有办法找回吗? (或者还有其他一些我完全没有想到的优雅方式吗?)
问题本身并不是 compactMap
。有两个问题:
如果你想让序列懒惰地调用compactMap
,你需要使用lazy
.
看来 first
正在阻止懒惰行为。但是,如果您使用 first(where:)
,您确实会喜欢这种懒惰的行为。
因此,虽然有些不雅,但以下内容可以满足您的需求:
if let vc = (chain.lazy.compactMap { [=10=] as? ViewController }.first { _ in true } ) {
...
}
或者,如您所说,您可以在 Sequence
上实施 first
(或 lazyFirst
):
extension Sequence {
var first: Element? {
return first { _ in true }
}
}
然后这个更简化的演绎现在仍然是懒惰的:
if let vc = chain.lazy.compactMap({ [=12=] as? ViewController }).first {
...
}
每隔一段时间,我必须沿着响应链向上走,才能到达已知 class 的实例。 (只是为了问题的目的接受这个。)我一直在用一个 while 循环来做这个,但我想到使用 sequence()
会更酷,它可以像这样整齐地表达响应者链本身:
let chain = sequence(first: someView as UIResponder) {[=10=].next}
这太棒了,因为到目前为止我们还没有真正走过任何路;该序列是惰性的,直到我们开始请求元素时才会执行匿名函数。为了证明这一点,让我用打印语句检测该代码:
let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}
好的,假设我正在寻找链中的第一个 ViewController 实例。我可以这样找到它:
if let vc = (chain.first {[=12=] 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{ [=14=] as? ViewController }.first) {
print(vc)
}
它的工作原理是它编译并得到正确的答案并且看起来不错,但我已经 失去了懒惰 。正在遍历整个chain
。 compactMap
是否失去懒惰?有办法找回吗? (或者还有其他一些我完全没有想到的优雅方式吗?)
问题本身并不是 compactMap
。有两个问题:
如果你想让序列懒惰地调用
compactMap
,你需要使用lazy
.看来
first
正在阻止懒惰行为。但是,如果您使用first(where:)
,您确实会喜欢这种懒惰的行为。
因此,虽然有些不雅,但以下内容可以满足您的需求:
if let vc = (chain.lazy.compactMap { [=10=] as? ViewController }.first { _ in true } ) {
...
}
或者,如您所说,您可以在 Sequence
上实施 first
(或 lazyFirst
):
extension Sequence {
var first: Element? {
return first { _ in true }
}
}
然后这个更简化的演绎现在仍然是懒惰的:
if let vc = chain.lazy.compactMap({ [=12=] as? ViewController }).first {
...
}