提问人:mike rodent 提问时间:11/14/2023 更新时间:11/14/2023 访问量:57
跳出 Vec::retain()?
jump out of Vec::retain()?
问:
我想遍历 a 对其中的对象执行各种操作(这将比 s 更复杂),并且在命令停止迭代的情况下,只保留尚未处理的对象。Vec
usize
fn main() {
let _ = iterate();
}
fn iterate(){
let mut objs_for_processing = Vec::new();
for i in 0..10 {
objs_for_processing.push(i);
}
let mut n = 0;
objs_for_processing.retain(|obj| {
n += 1;
if n > 3 {
println!("STOP iteration!...");
return true // i.e. retain
}
println!("iteration, do some business with obj {}", obj);
false
});
println!("objs_for_processing.len() {} {:#?}", objs_for_processing.len(), objs_for_processing);
}
很明显,上述的问题在于,即使你知道要保留所有其他元素,你也必须完成所有的迭代......
我找到了这个问题和这个问题。后者似乎更有前途。但后来事实证明,据我所知,您无法更改 's 闭包的返回类型(即接受 ,因此您可以返回 which 将停止迭代)。retain
Result
Err
我发现的唯一解决方案是克隆 ,使用正常迭代,然后在处理项目时从克隆中删除项目(称为 ),使用相当繁琐的Vec
for ... in
depleted_vec
let index = depleted_vec.iter().position(|x| x == obj).unwrap();
depleted_vec.remove(index);
...,然后分配给 .至少这样我就可以用它来停止迭代。objs_for_processing
depleted_vec
break
这似乎是一件相当合理的事情:难道没有更优雅的方法可以做到这一点吗?
注意:我也想知道是否可能有一个基于的解决方案,所以我尝试了......这会产生 的 ,而不是 。因此,也许可以使用它,但需要额外处理。不漂亮:只是感觉应该有更好的东西。Iterator
iter().filter(...).collect()
Vec
&usize
usize
答:
你不需要克隆 ,你只需使用索引进行迭代并删除元素:Vec
let mut i = 0;
let mut n = 0;
while i < objs_for_processing.len() {
if n > 3 {
println!("STOP iteration!...");
break;
}
if true {
let obj = &objs_for_processing[i];
println!("iteration, do some business with obj {}", obj);
objs_for_processing.remove(i);
// Don't increment `i`!
} else {
i += 1;
}
n += 1;
}
这不会像(因为它可以批量删除)那样有效,但这对您来说可能无关紧要。retain()
评论
i += 1;
因此,如果我理解正确,您需要做两件事:
- 遍历 vec 的元素,对那里的对象做事(修改它们?
- 在迭代过程中的某个时刻,某些东西会迫使您停止(例如,缓冲区已满)。此时,您希望从 vec 中删除所有已处理的项目,以便稍后可以恢复工作。
以下是有效完成此操作的循环:
let mut n = 0;
for e in &objs_for_processing {
if must_stop() { break; }
n += 1;
process(e);
}
objs_for_processing.drain(0..n);
我认为想出其他任何东西都没有意义,尽管实验性 API 可以很好地服务于您的用例(尽管仍然会迭代所有内容)。extract_if
但是,如果这真的是一个工作队列,那么最好首先使用 VecDeque。
use std::collections::VecDeque;
fn main() {
let mut objs_for_processing = (0..10).collect::<VecDeque<_>>();
let mut n = 0;
while let Some(obj) = objs_for_processing.pop_front() {
n += 1;
if n > 3 {
println!("STOP iteration!...");
break;
}
println!("iteration, do some business with obj {}", obj);
}
println!(
"objs_for_processing.len() {} {:#?}",
objs_for_processing.len(),
objs_for_processing
);
}
评论
Vec::drain
VecDeque
for
VecDeque
drain
Vec
Vec
Vec
Vec
评论
iter()
into_iter
into_iter
Vec
collect
objs_for_processing = objs_for_processing.into_iter().filter(|obj| { ...
filter
drop
filter