我正在寻找中断无限迭代器迭代的方法。我发现这try_fold
达到了我的目标。然而,这需要Err
在成功的案例上做返回一个尴尬的事情。我想了解的是,这是否是一种惯用的做事方式。我能想到的唯一另一种方法是使用常规的for
,或者像find
while 保持外部状态的东西(感觉更奇怪!)。我知道在 clojure 中有reduced
,但我找不到 rust 的等价物。
这是一个最小可行的例子。该示例围绕初始 Vec 循环,对每个项目进行求和,并在第一个大于 10 的总和处停止。即它返回 12,因为1 + 5 - 3 + 1 + 5 - 3 + 1 + 5 = 12
:
fn main() {
let seed = vec![1, 5, -3];
let res = seed.iter().cycle().try_fold(0, |accum, value| {
let next = accum + value;
if next > 10 {
Err(next)
} else {
Ok(next)
}
});
if let Err(res) = res {
println!("{:?}", res);
} else {
unreachable!();
}
}
Run Code Online (Sandbox Code Playgroud)
(游乐场链接)
对我来说感觉很奇怪的部分是if let Err(res) = res
成为积极条件并且真的是退出循环的唯一途径(因此为什么另一个分支无法访问)。
有没有更好的办法?
您可以使用scan
和find
:
fn main() {
let seed = vec![1, 5, -3];
let res = seed
.iter()
.cycle()
.scan(0, |accum, value| {
*accum += value;
Some(*accum)
})
.find(|&x| x > 10)
.unwrap();
println!("{:?}", res);
}
Run Code Online (Sandbox Code Playgroud)
这实际上比使用fold_while
from稍微短一些itertools
,如下所示:
use itertools::{FoldWhile::{Continue, Done}, Itertools};
fn main() {
let seed = vec![1, 5, -3];
let res = seed
.iter()
.cycle()
.fold_while(0, |accum, value| {
let next = accum + value;
if next > 10 {
Done(next)
} else {
Continue(next)
}
})
.into_inner();
println!("{:?}", res);
}
Run Code Online (Sandbox Code Playgroud)
简单,正常迭代即可
fn main() {
let seed = vec![1, 5, -3];
let mut accum = 0;
for value in seed.iter().cycle() {
accum += value;
if accum > 10 {
break;
}
}
println!("{:?}", accum)
}
Run Code Online (Sandbox Code Playgroud)
小智 2
如果您不介意使用完善的外部库,请考虑使用itertools::fold_while 。如果您喜欢这种编程风格,可能还有其他有用的扩展。