Ir al contenido

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.

fn main() {
let mut count = 0;
loop {
count += 1;
println!("{count}");
if count == 3 {
break;
}
}
}

Salida:

1
2
3
▶ Pruébalo tú mismo

loop 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.

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:

20
▶ Pruébalo tú mismo

Es 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;.

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 64
▶ Pruébalo tú mismo

Con 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.

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.

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!
▶ Pruébalo tú mismo

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 veces
▶ Pruébalo tú mismo

break 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.

  • loop repite para siempre hasta que un break lo detiene: asegúrate siempre de que haya uno.
  • break valor; detiene el bucle y devuelve valor como resultado de toda la expresión loop.
  • Escribe loop, no while true: Rust sabe que el cuerpo de un loop siempre se ejecuta, y eso le ayuda a comprobar tus variables.
  • Recurre a loop cuando repites “hasta que pase algo”, no cuando cuentas un número conocido de veces.

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