Rust é uma linguagem conhecida por sua segurança, desempenho e expressividade. Uma de suas características mais poderosas é o sistema de iteradores, que permite processar coleções de dados de maneira eficiente e declarativa. Neste artigo, vamos explorar o que são iteradores, como usá-los em Rust e como eles podem ser aplicados para resolver problemas comuns de programação.
O Que São Iteradores?
Iteradores são objetos que permitem percorrer uma sequência de elementos, um de cada vez. Em Rust, eles são representados pelo tipo Iterator
, que fornece uma API robusta para manipular coleções sem a necessidade de escrever laços explícitos. O grande diferencial está no foco em lazy evaluation, o que significa que as operações de um iterador são executadas apenas quando necessário.
Um exemplo simples de iterador:
let numeros = vec![1, 2, 3, 4]; let iterador = numeros.iter(); // Cria um iterador
for numero in iterador { println!("{}", numero); }
Como Iteradores Funcionam?
Rust fornece dois métodos principais para criar e consumir iteradores:
iter()
: Cria um iterador que empresta os valores da coleção.into_iter()
: Consome a coleção e transforma os valores em propriedade do iterador.iter_mut()
: Cria um iterador mutável, permitindo alterar os valores da coleção.
Exemplo de uso de iter_mut
:
let mut numeros = vec![1, 2, 3, 4];
for numero in numeros.iter_mut() {
*numero *= 2; // Dobra o valor de cada número
}
println!("{:?}", numeros); // [2, 4, 6, 8]
Métodos Comuns de Iteradores
Rust oferece uma ampla variedade de métodos para manipular iteradores. Aqui estão os mais populares:
map
: Transforma os elementos de um iterador.filter
: Seleciona elementos que satisfazem uma condição.collect
: Converte um iterador em uma coleção.fold
: Reduz os elementos do iterador a um único valor.
Exemplo combinando map
e filter
:
let numeros = vec![1, 2, 3, 4, 5, 6];
let resultado: Vec<_> = numeros
.iter()
.map(|x| x * x) // Eleva ao quadrado
.filter(|x| x % 2 == 0) // Mantém apenas os pares
.collect();
println!("{:?}", resultado); // [4, 16, 36]
Iteradores e Performance
Uma das vantagens do sistema de iteradores de Rust é que ele combina lazy evaluation com otimizações do compilador, gerando código altamente eficiente. Operações encadeadas, como map
e filter
, não criam coleções intermediárias; em vez disso, o Rust as processa como uma única operação.
Criando Seu Próprio Iterador
Você também pode criar iteradores personalizados implementando o trait Iterator
. Um exemplo simples é um iterador que gera números pares:
struct Pares {
atual: u32,
}
impl Iterator for Pares {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.atual += 2;
Some(self.atual)
}
}
fn main() {
let mut pares = Pares { atual: 0 };
for numero in pares.take(5) {
println!("{}", numero);
}
}
Iteradores x Laços
Embora você possa usar laços como for
e while
, iteradores são uma alternativa mais declarativa e menos propensa a erros. Além disso, eles permitem compor operações de maneira elegante, tornando o código mais legível e expressivo.
Exemplo com laço tradicional:
let numeros = vec![1, 2, 3];
let mut soma = 0;
for numero in &numeros {
soma += numero;
}
println!("{}", soma);
Equivalente com Iterator
:
let numeros = vec![1, 2, 3];
let soma: i32 = numeros.iter().sum();
println!("{}", soma);
Conclusão
Os iteradores são uma das ferramentas mais poderosas do ecossistema Rust. Eles permitem manipular coleções com elegância, eficiência e segurança, aproveitando ao máximo os recursos da linguagem. Seja você iniciante ou experiente em Rust, explorar o sistema de iteradores é um passo essencial para escrever código mais idiomático e performático.