<h2>Por que Implementar Iteradores Customizados?</h2>
<p>Iteradores são fundamentais em linguagens funcionais e modernas como Rust, Python e JavaScript. Em Rust, o trait <code>Iterator</code> permite criar loops eficientes e expressivos sobre estruturas de dados personalizadas. Quando você implementa o trait <code>Iterator</code>, seu tipo se integra perfeitamente com o ecossistema Rust, funcionando com <code>for</code>, métodos como <code>map()</code>, <code>filter()</code> e <code>collect()</code>. Isso não é apenas conveniência sintática — é performance garantida com zero-cost abstractions.</p>
<p>Neste artigo, vamos construir iteradores reais, entender o trait <code>Iterator</code> por dentro e aprender quando e como usá-los. Você sairá daqui sabendo implementar iteradores para suas próprias estruturas de dados.</p>
<h2>Entendendo o Trait Iterator</h2>
<h3>A Anatomia do Trait</h3>
<p>O trait <code>Iterator</code> em Rust é simples mas poderoso. Ele requer apenas um método obrigatório: <code>next()</code>, que retorna <code>Option<Self::Item></code>. O tipo associado <code>Item</code> define o tipo de elemento que o iterador produz.</p>
<pre><code class="language-rust">pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// Métodos padrão (map, filter, collect, etc.)
// todos construídos sobre next()
}</code></pre>
<blockquote><p>A elegância aqui: todos os métodos convenientes derivam de <code>next()</code>. Implementar um método bem feito oferece dezenas de operações de graça.</p></blockquote>
<h3>Implementação Básica</h3>
<p>Vamos criar um iterador para uma sequência de números pares:</p>
<pre><code class="language-rust">struct ContadorPares {
inicio: u32,
fim: u32,
}
impl ContadorPares {
fn new(inicio: u32, fim: u32) -> Self {
ContadorPares { inicio, fim }
}
}
impl Iterator for ContadorPares {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.inicio < self.fim {
if self.inicio % 2 == 0 {
let resultado = self.inicio;
self.inicio += 1;
Some(resultado)
} else {
self.inicio += 1;
self.next() // recursão para pular ímpares
}
} else {
None
}
}
}
fn main() {
let contador = ContadorPares::new(0, 10);
for num in contador {
println!("{}", num); // 0, 2, 4, 6, 8
}
}</code></pre>
<p>Note que o loop <code>for</code> funciona automaticamente. Rust reconhece que <code>ContadorPares</code> implementa <code>Iterator</code> e desaçúcar o loop para chamadas sucessivas de <code>next()</code>.</p>
<h2>Iteradores em Estruturas de Dados</h2>
<h3>Iterando Sobre Estruturas Personalizadas</h3>
<p>Frequentemente você quer iterar sobre uma coleção própria. Considere uma lista ligada customizada:</p>
<pre><code class="language-rust">struct No<T> {
valor: T,
proximo: Option<Box<No<T>>>,
}
struct ListaLigada<T> {
cabeca: Option<Box<No<T>>>,
}
struct IteradorLista<T> {
no_atual: Option<&'a Box<No<T>>>,
}
impl<T> ListaLigada<T> {
fn iter(&self) -> IteradorLista<T> {
IteradorLista {
no_atual: self.cabeca.as_ref(),
}
}
}
impl<'a, T> Iterator for IteradorLista<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.no_atual.map(|no| {
self.no_atual = no.proximo.as_ref();
&no.valor
})
}
}
fn main() {
let mut lista = ListaLigada { cabeca: None };
// Preenchimento da lista...
for valor in lista.iter() {
println!("{}", valor);
}
}</code></pre>
<p>Aqui usamos lifetimes (<code>'a</code>) para garantir que as referências retornadas pelo iterador vivem o tempo adequado. O método <code>map()</code> em <code>Option</code> é elegante: se houver um nó, retorna seu valor e avança; caso contrário, retorna <code>None</code> automaticamente.</p>
<h3>Iteradores Consumidores vs. Emprestados</h3>
<p>Há três padrões comuns:</p>
<ul>
<li><strong><code>iter()</code></strong>: retorna referências (não-mutáveis), a coleção permanece intacta</li>
<li><strong><code>iter_mut()</code></strong>: retorna referências mutáveis, permite modificação</li>
<li><strong><code>into_iter()</code></strong>: consome a coleção, transfere ownership</li>
</ul>
<pre><code class="language-rust">impl<T> ListaLigada<T> {
fn iter_mut(&mut self) -> IteradorListaMut<T> {
IteradorListaMut {
no_atual: self.cabeca.as_mut(),
}
}
}
impl<'a, T> Iterator for IteradorListaMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
self.no_atual.take().map(|no| {
self.no_atual = no.proximo.as_mut();
&mut no.valor
})
}
}</code></pre>
<h2>Operações Encadeadas e Performance</h2>
<h3>Composição de Métodos</h3>
<p>Um dos superpoderes do trait <code>Iterator</code> é a capacidade de encadear operações de forma limpa e <strong>eficiente</strong>. Veja:</p>
<pre><code class="language-rust">fn main() {
let pares = ContadorPares::new(0, 20)
.filter( | n | n % 3 != 0) // Remove múltiplos de 3 .map(|n| n * 2) // Dobra cada número
.take(5); // Pega apenas 5 primeiros
let resultado: Vec<u32> = pares.collect();
println!("{:?}", resultado);
}</code></pre>
<p>Isso não aloca intermediários como vetores temporários — é <strong>lazy evaluation</strong>. O iterador computaciona valores sob demanda, de forma eficiente em memória e CPU.</p>
<h3>Implementando Métodos Customizados</h3>
<p>Você pode adicionar métodos específicos ao seu iterador:</p>
<pre><code class="language-rust">trait IteratorExt: Iterator {
fn dobrar(self) -> Map<Self, fn(Self::Item) -> Self::Item>
where
Self: Sized,
{
self.map(|x: Self::Item| x * 2)
}
}
impl<I: Iterator> IteradorExt for I {}
// Uso:
let resultado: Vec<u32> = ContadorPares::new(1, 5)
.dobrar()
.collect();</code></pre>
<p>Aqui estendemos qualquer iterador com novos comportamentos sem modificar sua definição — isso é <strong>composição horizontal</strong> em ação.</p>
<h2>Conclusão</h2>
<p>Implementar o trait <code>Iterator</code> em Rust oferece três ganhos centrais:</p>
<ol>
<li><strong>Integração ecosistema</strong>: seu tipo funciona com <code>for</code>, <code>map()</code>, <code>filter()</code>, <code>collect()</code> — toda a linguagem passa a trabalhar com seus dados naturalmente.</li>
</ol>
<ol>
<li><strong>Eficiência garantida</strong>: lazy evaluation, zero-copy quando apropriado, e compilação otimizada pelo LLVM garantem performance em produção.</li>
</ol>
<ol>
<li><strong>Clareza expressiva</strong>: iteradores customizados transformam lógica complexa de percurso em código declarativo e legível, reduzindo bugs.</li>
</ol>
<p>O investimento em dominar <code>Iterator</code> se paga rapidamente. Toda estrutura de dados relevante em Rust implementa este trait — aprender a construir iteradores é aprender a linguagem na profundidade certa.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://doc.rust-lang.org/book/ch13-02-iterators.html" target="_blank" rel="noopener noreferrer">The Rust Book - Iterators</a></li>
<li><a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html" target="_blank" rel="noopener noreferrer">Rust std::iter::Iterator Documentation</a></li>
<li><a href="https://docs.rs/itertools/latest/itertools/" target="_blank" rel="noopener noreferrer">Itertools Crate — Extensões de Iteradores</a></li>
<li><a href="https://zsiciarz.github.io/24daysofrust/book/vol2/day1.html" target="_blank" rel="noopener noreferrer">24 Days of Rust — Iterators</a></li>
<li><a href="https://doc.rust-lang.org/rust-by-example/trait/iter.html" target="_blank" rel="noopener noreferrer">Rust by Example — Iterators</a></li>
</ul>