Rust Coleções Intermediário
Iteradores
Em Rust, iteradores são uma abstração poderosa para processar sequências de valores. Eles permitem encadear operações como map, filter e collect de forma declarativa e eficiente. O trait Iterator define um método next que retorna Option<Item>, e a partir dele dezenas de adaptadores são implementados.
Uma característica fundamental é a preguiça (lazy evaluation): adaptadores como map e filter não fazem nada até que um método consumidor (como collect, sum ou for_each) seja chamado. Isso possibilita otimizações e evita alocações desnecessárias.
Além de usar iteradores prontos, você pode implementar seu próprio iterador criando um tipo que implemente o trait Iterator. Isso é útil para percorrer estruturas customizadas ou gerar sequências sob demanda.
Neste card, vamos explorar desde o uso básico de map, filter e collect, entender a preguiça, e por fim implementar um iterador personalizado.
Pontos-chave
- O trait
Iteratorexige a implementação do métodonext, que retornaOption<Self::Item>. maptransforma cada elemento,filterseleciona elementos, ecollectconsome o iterador em uma coleção.- Iteradores são preguiçosos: adaptadores não executam nada até um consumidor ser chamado.
- Você pode implementar
Iteratorpara seus próprios tipos e ganhar todos os adaptadores de graça. iter()empresta,iter_mut()empresta mutavelmente einto_iter()consome a coleção.
fn main() {
let numeros = vec![1, 2, 3, 4, 5, 6];
// map + filter + collect: dobra os pares
let dobrados_pares: Vec<i32> = numeros
.iter()
.filter(|&&x| x % 2 == 0)
.map(|&x| x * 2)
.collect();
println!("Pares dobrados: {:?}", dobrados_pares);
// Iteradores são preguiçosos: nada acontece até consumir
let mut iter = numeros.iter().map(|&x| {
println!("Processando {}", x);
x * 10
});
println!("Antes de consumir");
let primeiro = iter.next(); // só aqui o primeiro é processado
println!("Primeiro: {:?}", primeiro);
// Implementando um iterador personalizado: contador até um limite
struct ContadorAte {
atual: u32,
limite: u32,
}
impl Iterator for ContadorAte {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.atual < self.limite {
let valor = self.atual;
self.atual += 1;
Some(valor)
} else {
None
}
}
}
let contador = ContadorAte { atual: 0, limite: 3 };
let valores: Vec<u32> = contador.collect();
println!("Contador: {:?}", valores);
}