Cuando implementas el trait Iterator para un tipo, solo defines un método: next(). A cambio, obtienes gratis más de setenta métodos: map, filter, collect, enumerate, zip, take, fold
Cualquier código que acepte un iterador aceptará el tuyo automáticamente.
Contador básico
struct Contador {
valor: u32,
max: u32,
}
impl Contador {
fn new(max: u32) -> Self {
Contador { valor: 0, max }
}
}
impl Iterator for Contador {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.valor < self.max {
self.valor += 1;
Some(self.valor)
} else {
None
}
}
}
fn main() {
let c = Contador::new(5);
// Todos estos métodos vienen gratis
let suma: u32 = c.sum();
println!("Suma 1..5 = {}", suma); // 15
let dobles: Vec<_> = Contador::new(5).map(|x| x * 2).collect();
println!("{:?}", dobles); // [2, 4, 6, 8, 10]
let pares: Vec<_> = Contador::new(10).filter(|x| x % 2 == 0).collect();
println!("{:?}", pares); // [2, 4, 6, 8, 10]
}
Fibonacci infinito
struct Fibonacci {
a: u64,
b: u64,
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { a: 0, b: 1 }
}
}
impl Iterator for Fibonacci {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let siguiente = self.a + self.b;
self.a = self.b;
self.b = siguiente;
Some(self.a) // infinito: nunca devuelve None
}
}
fn main() {
// take() limita el iterador infinito
let fib: Vec<u64> = Fibonacci::new().take(10).collect();
println!("{:?}", fib); // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
// Primer Fibonacci mayor que 1000
let grande = Fibonacci::new().find(|&n| n > 1000);
println!("{:?}", grande); // Some(1597)
}
Árbol binario con recorrido en orden
enum Arbol {
Vacio,
Nodo { valor: i32, izq: Box<Arbol>, der: Box<Arbol> },
}
struct RecorridoEnOrden {
pila: Vec<i32>,
}
impl RecorridoEnOrden {
fn new(arbol: &Arbol) -> Self {
let mut pila = Vec::new();
Self::recopilar(arbol, &mut pila);
RecorridoEnOrden { pila }
}
fn recopilar(arbol: &Arbol, pila: &mut Vec<i32>) {
if let Arbol::Nodo { valor, izq, der } = arbol {
Self::recopilar(izq, pila);
pila.push(*valor);
Self::recopilar(der, pila);
}
}
}
impl Iterator for RecorridoEnOrden {
type Item = i32;
fn next(&mut self) -> Option<i32> {
if self.pila.is_empty() { None } else { Some(self.pila.remove(0)) }
}
}
IntoIterator: para usar en for loops
struct Rango {
inicio: i32,
fin: i32,
}
impl IntoIterator for Rango {
type Item = i32;
type IntoIter = std::ops::Range<i32>;
fn into_iter(self) -> Self::IntoIter {
self.inicio..self.fin
}
}
fn main() {
let r = Rango { inicio: 1, fin: 6 };
for n in r {
print!("{} ", n); // 1 2 3 4 5
}
}
Resumen
- Implementa solo
next() -> Option<Item>y obtienes más de 70 métodos gratis. - Los iteradores infinitos (que nunca devuelven
None) se limitan contake(). - Implementa
IntoIteratorpara que tu tipo funcione directamente en buclesfor. - El trait
Iteratores la abstracción más reutilizable del ecosistema Rust.
El siguiente artículo cubre Box<T>: cuándo necesitas asignar en el heap, cómo usar tipos recursivos y el dispatch dinámico con Box<dyn Trait>.
