iter vs into_iter: batalla de titanes de la iteración en Rust
\n\nSi alguna vez has escrito un bucle sobre un vector en Rust, seguramente te has encontrado con los tres hermanos gemelos: iter(), into_iter() y iter_mut(). A primera vista, todos hacen lo mismo: permiten recorrer los elementos. Pero la diferencia entre ellos es más profunda de lo que parece y se encuentra en el corazón de Rust: el sistema de propiedad.
Imagina que eres un barista y tu colección son granos de café. iter() te permite mirar los granos, olerlos, pero no tocarlos. into_iter() es cuando tomas los granos, los mueles y haces un espresso, después de lo cual los granos desaparecen. Y iter_mut() — puedes no solo mirar, sino también moler los granos directamente en la bolsa, cambiando su forma.
Hoy analizaremos iter vs into_iter como se explica en Stack Overflow, pero con ejemplos vivos y una inmersión profunda bajo el capó. ¡Allá vamos!
\n\n¿Qué es un iterador en Rust?
\n\nUn iterador es un objeto que sabe cómo obtener elementos secuencialmente de una colección. En Rust, los iteradores son perezosos: no hacen nada hasta que llamas a next(). Pero lo principal es que cada método de iteración trata la propiedad de los datos de manera diferente.
Aquí están los tres enfoques principales:
\n- \n
iter()— toma prestados los elementos (no toma la propiedad) \n into_iter()— consume la colección (toma la propiedad) \n iter_mut()— toma prestado con posibilidad de modificación \n
Veamos el código. Supongamos que tenemos un vector de nombres:
\n\nlet names = vec!["Ana".to_string(), "Boris".to_string(), "Víctor".to_string()];\n\nEjemplo 1: iter() — solo mirar
\n\nfn main() {\n let names = vec!["Ana".to_string(), "Boris".to_string(), "Víctor".to_string()];\n \n // iter() devuelve &String (una referencia)\n for name in names.iter() {\n println!("¡Hola, {}!", name);\n }\n \n // ¡names todavía está disponible!\n println!("El vector vive: {:?}", names);\n}\n\nObserva: después del bucle, usamos names sin problemas. ¿Por qué? Porque iter() devolvió una referencia a cada elemento. La propiedad permaneció en el vector. Esto es seguro y predecible.
Ejemplo 2: into_iter() — quemar los puentes
\n\nfn main() {\n let names = vec!["Ana".to_string(), "Boris".to_string(), "Víctor".to_string()];\n \n // into_iter() devuelve String (la propiedad se mueve)\n for name in names.into_iter() {\n println!("¡Adiós, {}!", name);\n }\n \n // ¡Error! names ya no existe\n // println!("El vector vive: {:?}", names); // ❌ borrow of moved value\n}\n\nAhí está la diferencia clave. into_iter() consume la colección. Cada elemento se mueve al bucle y el vector original se vuelve inválido. Si necesitas conservar la colección para uso posterior, into_iter() no es tu opción.
Ejemplo 3: iter_mut() — modificar sin destruir
\n\nfn main() {\n let mut names = vec!["Ana".to_string(), "Boris".to_string(), "Víctor".to_string()];\n \n // iter_mut() devuelve &mut String (referencia mutable)\n for name in names.iter_mut() {\n name.push_str(" (invitado)");\n }\n \n println!("Vector modificado: {:?}", names);\n // Salida: ["Ana (invitado)", "Boris (invitado)", "Víctor (invitado)"]\n}\n\nAquí modificamos los elementos en su lugar, pero sin tomar la propiedad. Ideal para transformaciones.
\n\nBajo el capó: ¿qué devuelve cada método?
\n\nPara entender realmente iter vs into_iter, echemos un vistazo a la biblioteca estándar. Para el vector Vec<T>:
- \n
iter()devuelvestd::slice::Iter<T>— implementaIterator<Item = &T>
Blogs
Book Recommendations
Leer también
Rust para el aprendizaje automático: posibilidades y limitaciones
Pruebas en Java: unit, integration, e2e — guía completa