Quero iterar Vec
fazendo várias coisas com os objetos nele contidos (o que seria mais complexo que usize
s) e, no caso de uma ordem para interromper a iteração, reter apenas os objetos que ainda não foram processados.
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);
}
O problema acima, obviamente, é que você precisa completar todas as iterações, mesmo depois de saber que deseja manter todos os outros elementos...
Encontrei esta pergunta e esta pergunta . Este último parecia mais promissor. Mas acontece que você não pode alterar o tipo de retorno do retain
fechamento de ' (ou seja, aceitar a Result
, para poder retornar an Err
que interromperá a iteração), até onde eu sei.
A única solução que encontrei é clonar o Vec
, iterar usando um normal for ... in
e depois remover itens do clone (chamado depleted_vec
) à medida que são processados, usando o bastante complicado
let index = depleted_vec.iter().position(|x| x == obj).unwrap();
depleted_vec.remove(index);
... e depois atribuir objs_for_processing
a depleted_vec
. Pelo menos desta forma posso usar break
para interromper a iteração.
Parece uma coisa bastante razoável de se fazer: não existe uma maneira mais elegante de fazer isso?
NB: Eu também me perguntei se poderia haver uma Iterator
solução baseada em - então tentei com iter().filter(...).collect()
... isso produz um Vec
of &usize
, not usize
. Portanto, talvez pudesse ser usado, mas com custo de processamento adicional. Não é bonito: parece que deveria haver algo melhor.
Então, se bem entendi, você precisa fazer duas coisas:
Aqui está o loop para fazer isso de forma eficiente:
Não vejo sentido em sugerir mais nada, embora a
extract_if
API experimental serviria bem ao seu caso de uso (ainda assim iteraria sobre tudo).No entanto , se esta for realmente uma fila de trabalho, é muito melhor usar um VecDeque em primeiro lugar.
Link para o playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=78468b26d34a29009b090a969fd9d5f3
Você não precisa clonar o
Vec
, você pode apenas iterar usando índices e remover os elementos:Isso não será tão eficiente quanto
retain()
(pois pode fazer remoção em massa), mas provavelmente não importa para você.