Bucles en Rust
Rust tiene tres formas de repetir código: loop, while y for. Esta página trata sobre loop, la más simple y directa de las tres: repite para siempre hasta que le dices que pare.
Un loop básico
Sección titulada «Un loop básico»fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}Salida:
123loop por sí solo nunca se detiene: lo que lo termina es break. Sin ese if count == 3 { break; }, este programa imprimiría números para siempre.
Devolver un valor desde un loop
Sección titulada «Devolver un valor desde un loop»Esto es algo que loop puede hacer y while y for no: puedes poner un valor después de break, y ese valor se convierte en el resultado de todo el bucle:
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // para y devuelve un valor } };
println!("{result}");}Salida:
20Es muy práctico para cosas como “sigue intentándolo hasta que funcione y luego dame el resultado”. Verás este patrón en código real más de lo que imaginas.
Fíjate en el punto y coma después de la } que cierra el bucle. Todo el loop { ... } es la parte derecha de let result = ...;, así que la instrucción let necesita su ; al final, igual que let x = 5;.
¿Por qué loop y no while true?
Sección titulada «¿Por qué loop y no while true?»Si vienes de otro lenguaje, quizá escribirías un bucle infinito como while true { ... }. En Rust funciona, pero el compilador te avisa:
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`El aviso te pide que marques los bucles infinitos con loop { ... }. Y no es solo una cuestión de estilo. Rust sabe que el cuerpo de un loop siempre se ejecuta, y que la única forma de salir es un break. Con while true no lo da por hecho, porque no mira el valor de la condición. Eso marca una diferencia real cuando una variable recibe su valor dentro del bucle:
fn main() { let mut n = 1; let answer; // todavía sin valor
loop { if n * n > 50 { answer = n * n; // se lo damos justo antes de salir break; } n += 1; }
println!("El primer cuadrado mayor que 50 es {answer}");}Salida:
El primer cuadrado mayor que 50 es 64Con loop, Rust ve que la única forma de llegar al println! es pasando por ese break, así que answer siempre tiene valor. Cambia loop por while true y obtendrás error[E0381]: used binding answer is possibly-uninitialized, es decir, que answer podría no estar inicializada. El compilador cree que el bucle podría terminar sin ejecutar el if ni una vez.
En la práctica, la versión más limpia de este programa usa break con un valor, como viste arriba: let answer = loop { ... break n * n; ... };. En cualquier caso, la lección es la misma: cuando quieras decir “para siempre, hasta que haga break”, escribe loop.
Cuándo usar loop
Sección titulada «Cuándo usar loop»loop es la opción adecuada cuando no sabes de antemano cuántas veces vas a repetir: estás esperando a que se cumpla alguna condición, no recorriendo un rango o una lista. Para contar o recorrer una colección, while y for (los vemos a continuación) suelen leerse mejor.
Práctica
Sección titulada «Práctica»1. Cuenta atrás para el despegue
Sección titulada «1. Cuenta atrás para el despegue»Usa loop para imprimir una cuenta atrás de 5 a 1 y, después, ¡Despegue!. Pista: empieza con let mut n = 5; y haz break cuando n llegue a 0.
Ver solución
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("¡Despegue!");}Salida:
5...4...3...2...1...¡Despegue!La comprobación va primero, así que cuando n vale 0 el bucle se detiene antes de imprimir 0....
2. La primera potencia de dos mayor que 1000
Sección titulada «2. La primera potencia de dos mayor que 1000»Empieza en 1 y ve duplicando. Usa break con un valor para obtener el primer número mayor que 1000, y cuenta cuántas veces tuviste que duplicar. Pista: guarda un contador mut fuera del bucle y escribe let power = loop { ... };.
Ver solución
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("{power} tras duplicar {doublings} veces");}Salida:
1024 tras duplicar 10 vecesbreak value; termina el bucle y le entrega value a power. El contador vive fuera del bucle, así que conserva su valor cuando el bucle termina.
Resumen
Sección titulada «Resumen»looprepite para siempre hasta que unbreaklo detiene: asegúrate siempre de que haya uno.break valor;detiene el bucle y devuelvevalorcomo resultado de toda la expresiónloop.- Escribe
loop, nowhile true: Rust sabe que el cuerpo de unloopsiempre se ejecuta, y eso le ayuda a comprobar tus variables. - Recurre a
loopcuando repites “hasta que pase algo”, no cuando cuentas un número conocido de veces.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»Comprueba lo aprendido
1. ¿Qué impide que un loop a secas se ejecute para siempre?
2. ¿Qué consigues al escribir break count * 2; dentro de un loop?
3. Según esta página, ¿cuándo es mejor loop que while o for?
4. ¿Qué pasa si escribes while true { ... } en Rust?
Puntuación: 0 / 4
Para leer más
Sección titulada «Para leer más»- Repetición con bucles — El libro de Rust (en inglés): la introducción oficial a
loop,whileyfor. - Devolver valores desde bucles — El libro de Rust (en inglés): una sección corta sobre
breakcon un valor. - loop — Rust by Example (en inglés): ejemplos ejecutables de
loop,breakycontinue. - Devolver valores desde bucles — Rust by Example (en inglés): otro ejemplo pequeño de un bucle que devuelve un valor.
- La palabra clave
loop— documentación de la biblioteca estándar (en inglés): una referencia breve de cómo funcionan juntosloopybreak.