Los iteradores de Rust son lazy: no hacen nada hasta que los consumes. Ese diseño permite encadenar adaptadores sin crear colecciones intermedias, y el compilador optimiza la cadena completa hasta código equivalente a un bucle manual. Los artículos anteriores introdujeron map, filter y collect. Aquí veremos los adaptadores más útiles que van más allá de lo básico.
fold: acumular un resultado
fold es el adaptador más general. Cualquier iterador puede expresarse con él. Recibe un valor inicial y un closure que recibe el acumulador y el elemento actual:
fn main() {
let suma = (1..=5).fold(0, |acc, x| acc + x);
println!("{suma}"); // 15
// Producto de una lista
let producto = vec![1, 2, 3, 4, 5].iter().fold(1, |acc, x| acc * x);
println!("{producto}"); // 120
// Construir un String desde un iterador
let palabras = vec!["hola", "mundo", "rust"];
let frase = palabras.iter().fold(String::new(), |mut acc, w| {
if !acc.is_empty() { acc.push(' '); }
acc.push_str(w);
acc
});
println!("{frase}"); // hola mundo rust
}
chain: concatenar iteradores
fn main() {
let a = vec![1, 2, 3];
let b = vec![4, 5, 6];
let concatenado: Vec<_> = a.iter().chain(b.iter()).collect();
println!("{:?}", concatenado); // [1, 2, 3, 4, 5, 6]
// Útil para combinar iteradores de distintas fuentes
let errores = vec!["timeout", "connection refused"];
let advertencias = vec!["deprecated", "slow query"];
let todos: Vec<_> = errores.iter()
.chain(advertencias.iter())
.filter(|&&s| s.len() > 7)
.collect();
println!("{todos:?}"); // ["timeout", "connection refused", "deprecated", "slow query"]
}
zip: combinar dos iteradores en pares
fn main() {
let nombres = vec!["Ana", "Luis", "Eva"];
let puntos = vec![95, 87, 91];
let ranking: Vec<_> = nombres.iter().zip(puntos.iter()).collect();
for (nombre, pts) in &ranking {
println!("{nombre}: {pts}");
}
// Ana: 95 / Luis: 87 / Eva: 91
// zip se detiene en el iterador más corto
let corto = vec![1, 2, 3];
let largo = vec![10, 20, 30, 40, 50];
let pares: Vec<_> = corto.iter().zip(largo.iter()).collect();
println!("{pares:?}"); // [(1, 10), (2, 20), (3, 30)]
}
flat_map: mapear y aplanar
fn main() {
// Cada pedido tiene varios productos; queremos todos en una lista plana
let pedidos = vec![
vec!["manzana", "pan"],
vec!["leche"],
vec!["café", "azúcar", "galletas"],
];
let productos: Vec<_> = pedidos.iter().flat_map(|p| p.iter()).collect();
println!("{productos:?}");
// ["manzana", "pan", "leche", "café", "azúcar", "galletas"]
// flat_map equivale a map + flatten
let numeros = vec![1, 2, 3];
let expandido: Vec<_> = numeros.iter()
.flat_map(|&x| vec![x, x * 10])
.collect();
println!("{expandido:?}"); // [1, 10, 2, 20, 3, 30]
}
enumerate: índice junto al valor
fn main() {
let frutas = vec!["manzana", "pera", "naranja"];
for (i, fruta) in frutas.iter().enumerate() {
println!("{i}: {fruta}");
}
// 0: manzana / 1: pera / 2: naranja
// Buscar el índice de un elemento
let pos = frutas.iter().enumerate()
.find(|(_, &f)| f == "pera")
.map(|(i, _)| i);
println!("pera en posición: {pos:?}"); // Some(1)
}
take y skip: paginación
fn main() {
let articulos: Vec<i32> = (1..=100).collect();
let pagina = 2;
let por_pagina = 10;
let resultado: Vec<_> = articulos.iter()
.skip((pagina - 1) * por_pagina)
.take(por_pagina)
.collect();
println!("{resultado:?}"); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
}
El error típico con lazy evaluation
fn main() {
let _cadena = vec!["a", "b", "c"]
.iter()
.map(|s| { println!("procesando {s}"); s.to_uppercase() });
// No imprime nada: el iterador no se ha consumido
// Necesitas collect(), for_each(), sum(), etc. para ejecutarlo
let resultado: Vec<_> = vec!["a", "b", "c"]
.iter()
.map(|s| { println!("procesando {s}"); s.to_uppercase() })
.collect(); // Ahora sí ejecuta
println!("{resultado:?}");
}
Resumen
foldgeneraliza cualquier acumulación: suma, producto, strings, estructuras personalizadas.chainencadena iteradores sin asignar memoria intermedia.zipcombina dos iteradores en pares y se detiene en el más corto.flat_mapmapea y aplana en un solo paso, ideal para listas de listas.enumerateañade el índice sin romper la cadena.takeyskippermiten paginación limpia sin cortes manuales.- Los iteradores son lazy: sin un consumidor final no hacen nada.
