我有一个迭代器,我想在最终调用之前有条件地应用过滤器、跳过等collect()。
用不同的语言,我可能会写类似的东西
// (Rust-like pseudocode)
let mut iter = [1,2,3,4].iter();
if should_filter {
iter = iter.filter(|x| x % 2 == 0);
}
if should_truncate {
iter = iter.take(2);
}
iter.collect()
Run Code Online (Sandbox Code Playgroud)
但由于iter是 类型Iter, 并且skip()返回filter()类型Skip, Filter, 我无法重用 的原始绑定iter。结果,我的 Rust 代码目前看起来像这样:
// (Rust-like pseudocode)
let mut iter = [1,2,3,4].iter();
if should_filter {
iter = iter.filter(|x| x % 2 == 0);
}
if should_truncate {
iter = iter.take(2);
}
iter.collect()
Run Code Online (Sandbox Code Playgroud)
有什么办法可以避免这种重复吗?
在这种情况下,您可以可靠地信任编译器的优化循环不变量。由于should_filter迭代时无法更改,编译器将发现它可以在循环之前检查前提条件并跳过测试 if should_filteris true。这意味着您可以简单地将条件放入循环中(这似乎效率低下)并且拥有更清晰的代码。即使检查没有从循环体中删除,CPU 的分支预测器也会轻松跳过它。同样,您可以“内联”should_truncate条件:
fn do_stuff(
inp: impl IntoIterator<Item = u32>,
should_filter: bool,
should_truncate: bool,
) -> Vec<u32> {
inp.into_iter()
.filter(|x| should_filter && x % 2 == 0)
.take(if should_truncate { 2 } else { usize::MAX })
.collect()
}
Run Code Online (Sandbox Code Playgroud)
最简单的解决方案,也可能最接近您的“其他语言”在幕后所做的事情,就是对迭代器进行装箱:
let mut iter: Box<dyn Iterator<Item = &i32>> = Box::new ([1, 2, 3, 4].iter());
if should_filter {
iter = Box::new (iter.filter(|x| *x % 2 == 0));
}
if should_truncate {
iter = Box::new (iter.take(2));
}
let v: Vec<_> = iter.collect();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1050 次 |
| 最近记录: |