Iteración sobre Vec con índice en Rust: 4 formas de comparar

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Iteración sobre Vec con índice en Rust: de principiante a experto



Imagina: estás escribiendo en Rust y necesitas recorrer los elementos de un vector, pero también conocer no solo el valor, sino también su posición. Parece una tarea simple, pero a menudo desconcierta a los principiantes. ¿Dónde está el for i in range(len(vec)), como en Python? ¿Y si quiero modificar elementos? ¿Y qué es más rápido?



En este artículo analizaremos todas las formas populares de iterar sobre Vec con índice en Rust, compararemos su rendimiento, legibilidad y seguridad. Aprenderás qué método elegir en 2024 y por qué enumerate no siempre es la bala de plata.



¿Por qué es importante?

En Rust no existe el clásico for i in 0..vec.len() como único camino correcto. El lenguaje ofrece varios paradigmas: desde iteradores funcionales hasta bucles de bajo nivel. Comprender la diferencia entre ellos es clave para escribir código eficiente e idiomático. Esto es especialmente crítico al trabajar con vectores, donde el índice puede ser necesario para modificar elementos vecinos o rastrear la posición en un algoritmo.



Método 1: El clásico — enumerate

La forma más común y recomendada. El método enumerate envuelve el iterador, añadiendo su índice a cada elemento:



let vec = vec!["a", "b", "c", "d"];for (index, value) in vec.iter().enumerate() {    println!("Posición {}: {}", index, value);}


Ventajas:

  • Idiomático y legible
  • Seguro: sin riesgo de salirse de los límites
  • Funciona con cualquier iterador, no solo con Vec

Desventajas: No se pueden modificar directamente los elementos del vector (se necesita iter_mut()).



Método 2: Por índices — 0..vec.len()

Enfoque familiar para todos desde C++ o Python. Usamos un rango de índices:



let mut vec = vec![10, 20, 30, 40];for i in 0..vec.len() {    vec[i] += i; // modificamos el elemento por índice    println!("vec[{}] = {}", i, vec[i]);}


Ventajas:

  • Control total sobre el índice y el elemento
  • Se pueden modificar elementos mediante vec[i]
  • Intuitivo para principiantes

Desventajas: Más lento que los iteradores (verificación adicional de límites). La comunidad Rust lo considera "no idiomático".



Método 3: while con contador

La forma más "manual", que encontrarás en código antiguo o durante optimizaciones:



let vec = vec![1.0, 2.0, 3.0];let mut i = 0;while i < vec.len() {    println!("Elemento {}: {}", i, vec[i]);    i += 1;}


Ventajas: Máxima flexibilidad (se puede saltar entre índices, cambiar el paso).

Desventajas: Fácil cometer errores con la condición. No recomendado sin una razón de peso.



Método 4: zip con rango

Enfoque funcional, útil cuando se necesita iterar dos vectores en paralelo con índices:



let names = vec!["Alice", "Bob", "Charlie"];let scores = vec![95, 87, 92];

for (i, (name, score)) in (0..).zip(names.iter()).zip(scores.iter()) { println!("{}: {} obtuvo {} puntos", i, name, score);}


Ventajas: Potente para iteración paralela. El rango infinito 0.. se recorta automáticamente.

Desventajas: Puede ser difícil de leer. Excesivo para tareas simples.



Comparación de rendimiento

Ejecutamos benchmarks en un vector de 100 000 elementos (optimización --release):



Blogs

Book Recommendations

MétodoTiempo (ns)Velocidad relativa
enumerate~12 0001.0x (referencia)
0..len~15 0001.25x más lento