我有一个应用于初始迭代器的迭代器适配器链(我不知道编译时的数量)。 一个简化的示例是通过整除性过滤一系列数字并获取最后剩余数字的数量:
let n: usize = 10;
let mut iter_chain: Box<dyn std::iter::Iterator<Item = usize>> = Box::new(1..=n);
for i in 2..n {
iter_chain = Box::new(iter_chain.filter(move |j| j % i != 0));
}
println!("{}", iter_chain.count());
现在,我想计算该过滤器链的每个stage中的元素数量。
我的想法是在每个过滤器之间插入一个inspect
适配器,增加相应阶段的计数器。 然而,每个
inspect
适配器都必须从循环之外的某个地方借用可变计数器。 这导致了我当前存储计数器的 Vector 的多次相互借用。
let n: usize = 10;
let mut iter_chain: Box<dyn std::iter::Iterator<Item = usize>> = Box::new(1..=n);
let mut filter_overview = vec![0; n];
for i in 2..n {
// cannot borrow `filter_overview` as mutable more than once at a time
// |
// V
iter_chain = Box::new(iter_chain.inspect(|_| filter_overview[i] += 1));
iter_chain = Box::new(iter_chain.filter(move |j| j % i != 0));
}
println!("{filter_overview:?} {}", iter_chain.count());
本例中 filter_overview
的预期值为
[10, 5, 3, 3, 2, 2, 1, 1]
。这个问题有解决方法吗,或者我是否必须使用与 Vector 不同的东西来存储这些计数器? 也许有一种完全不同的方法来实现这一目标?
Arc<Vec<AtomicU64>>
(或您选择的任何原子类型)。结果看起来像(Playground 链接):
use std::sync::{
atomic::{AtomicU64, Ordering},
Arc,
};
fn main() {
let n: usize = 10;
let mut iter_chain: Box<dyn Iterator<Item = usize>> = Box::new(1..=n);
// AtomicU64 isn't Clone, so can't use vec![] syntax.
let filter_overview = Arc::new(Vec::from_iter(
std::iter::repeat_with(|| AtomicU64::new(0))
.take(n)
));
for i in 2..n {
// Get a fresh reference by cloning the Arc.
let overview = filter_overview.clone();
// Use a move closure to move the new Arc into the iterator.
iter_chain = Box::new(iter_chain.inspect(move |_| {
overview[i].fetch_add(1, Ordering::Relaxed);
}));
iter_chain = Box::new(iter_chain.filter(move |j| j % i != 0));
}
println!("{filter_overview:?} {}", iter_chain.count());
println!("Desired output: {:?}", [10, 5, 3, 3, 2, 2, 1, 1]);
}
输出是
[0, 0, 10, 5, 3, 3, 2, 2, 1, 1] 1
Desired output: [10, 5, 3, 3, 2, 2, 1, 1]