我不知道为什么在下面的代码中,第一次遇到的迭代没有停止None(到达空范围后0..0)
fn main() {
let iter = (0..)
.flat_map(move |i| if i < 10 { (0..i).into_iter() } else { 0..0 })
.fuse();
for i in iter {
println!("{}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
Playground报告它必须被杀死,它为什么不停止?如何让它停止?
flat_map()是执行此任务的错误工具。它旨在展平迭代器的迭代器,即每当它遇到None内部迭代器时,它的工作就是切换到下一个迭代器。如果你继续给它提供空迭代器,它会一直循环,直到找到一个非空的迭代器来传递值。flat_map()只会在外部时终止迭代迭代器执行,在您的情况下永远不会发生。
您需要做两件事:首先,以除空迭代器以外的其他方式标记迭代的结束——例如,使用OptionwhereSome表示“这是给你的另一个迭代器”,并None表示“我不再对迭代感兴趣,你可以终止”。其次,您需要在展平步骤之前终止迭代,使用有能力这样做的适配器,例如take_while()或scan()。
这是对您的代码的修改,该修改在i达到 10后终止:
fn main() {
let iter = (0..)
.map(move |i| if i < 10 { Some(0..i) } else { None })
.scan((), |_, item| item)
.flatten();
for i in iter {
println!("{}", i);
}
}
Run Code Online (Sandbox Code Playgroud)
这里flat_map()分为三个部分:第一部分在我们想要迭代时map()产生Some(inner_iterator),None当我们不再迭代时产生。然后来scan()将迭代器转换为一个next()只返回闭包返回值的迭代器。由于闭包返回item(包含在选项中的内部迭代器)不变,Some(inner_iterator)将通过,并将None作为迭代结束信号传播。最后,flatten()将内部迭代器生成的项目汇集到一个迭代器中,就像flat_map()在您的原始代码中所做的那样。
如果你真的想在第一个空的内部迭代器上终止,也可以通过提取第一个值scan()并测试它来安排:
// using 1.. to avoid immediately terminating on 0..0
let iter = (1..)
.map(move |i| if i < 10 { 0..i } else { 0..0 })
.scan((), |_, mut inner| match inner.next() {
Some(first) => Some(once(first).chain(inner)),
None => None,
})
.flatten();
Run Code Online (Sandbox Code Playgroud)
请注意,这fuse()不是您想要的。其目的是允许迭代器在耗尽后安全查询。通常,如果在迭代器next()已经返回后调用它,迭代器可能会发生恐慌None。fuse()扩展迭代器契约以允许next()在它已经返回后调用None。这是通过内部迭代器的单独标志实现的,并在next(). 如果没有查询迭代器就返回之后None哪位一个for循环doesn't,那么你就没有必要fuse()。