Lección 05 de 26 Primeros pasos
Control de flujo: if, loop, while y for
- if elige un camino según una condición, que siempre es un bool. Con 22 grados, temperatura > 30 es false.
- loop repite su bloque sin fin hasta que lo paras con break. Aquí, al llegar a 3 intentos.
- while repite mientras la condición sea cierta. Cuando cuenta llega a 0, el bucle termina y... ¡despegue!
- for recorre un rango de uno en uno. 1..4 incluye el 1 pero no el 4: da 3 vueltas.
Hasta ahora tus programas se ejecutaban de arriba abajo, línea a línea. Con el control de flujo decides qué código se ejecuta según una condición y cuántas veces se repite.
Rust tiene if para tomar decisiones y tres tipos de bucle: loop, while y for. Y, como viste en la lección anterior, casi todo en Rust es una expresión, así que if y loop también pueden devolver un valor.
if, else if y else
fn main() {
let temperatura = 22;
if temperatura > 30 {
println!("Hace calor");
} else if temperatura > 15 {
println!("Se está bien");
} else {
println!("Hace frío");
}
}- La condición no lleva paréntesis. Puedes ponerlos, pero el compilador te avisará de que sobran.
- Las llaves son obligatorias, aunque el bloque tenga una sola línea.
- Las condiciones se comprueban en orden y solo se ejecuta el primer bloque cuya condición se cumple.
Para escribir condiciones tienes los operadores de comparación ==, !=, <, >, <= y >=, que puedes combinar con && (y), || (o) y ! (no).
La condición tiene que ser un bool
En JavaScript o Python un número o un texto pueden usarse como condición: son los valores truthy y falsy. En Rust no existen: la condición tiene que ser un bool.
fn main() {
let mensajes = 3;
if mensajes {
println!("Tienes mensajes");
}
}error[E0308]: mismatched types
--> src/main.rs:4:8
|
4 | if mensajes {
| ^^^^^^^^ expected `bool`, found integerLa solución es escribir la comparación que quieres hacer: if mensajes > 0. Es algo más largo, pero no deja lugar a dudas.
if como expresión
Como if es una expresión, puedes usar su resultado directamente, por ejemplo para dar valor a una variable:
fn main() {
let edad = 15;
let entrada = if edad >= 18 { "general" } else { "reducida" };
println!("Entrada {entrada}");
}Cada rama es un bloque y su valor es su última expresión, igual que en las funciones. Por eso Rust no necesita el operador ternario (condicion ? a : b) de otros lenguajes.
Las dos ramas tienen que devolver el mismo tipo, porque el compilador necesita saber el tipo de la variable sin ejecutar el programa:
fn main() {
let lleno = true;
let valor = if lleno { 100 } else { "vacío" };
println!("{valor}");
}error[E0308]: `if` and `else` have incompatible typesloop: repetir hasta que lo pares
loop repite su bloque indefinidamente, hasta que lo detienes con break:
fn main() {
let mut intentos = 0;
loop {
intentos += 1;
println!("Intento {intentos}");
if intentos == 3 {
break;
}
}
}loop también es una expresión: el valor que pongas después de break es el que devuelve el bucle. Es muy útil para repetir algo hasta conseguir un resultado:
fn main() {
let mut contador = 0;
let resultado = loop {
contador += 1;
if contador == 10 {
break contador * 2;
}
};
println!("Resultado: {resultado}");
}Además de break, tienes continue, que salta directamente a la siguiente vuelta del bucle sin ejecutar el resto del bloque.
while: repetir mientras se cumpla algo
while comprueba una condición antes de cada vuelta y se detiene cuando deja de cumplirse:
fn main() {
let mut cuenta = 3;
while cuenta > 0 {
println!("{cuenta}...");
cuenta -= 1;
}
println!("¡Despegue!");
}Podrías conseguir lo mismo con loop, un if y un break, pero while se lee mucho mejor.
for: recorrer rangos y arrays
for es el bucle que más usarás. Recorre uno a uno los elementos de algo que se pueda recorrer, como un rango de números:
fn main() {
for i in 1..4 {
println!("Vuelta {i}");
}
}Un rango inicio..fin incluye el inicio pero no el final: 1..4 recorre 1, 2 y 3. Para incluir el final, usa ..=. Y para recorrerlo al revés, .rev():
La cuenta atrás de antes, con for, queda así:
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("¡Despegue!");
}Los paréntesis son necesarios para que .rev() se aplique al rango entero.
Recorrer un array
for también recorre directamente los elementos de un array, sin índices:
fn main() {
let lenguajes = ["Rust", "Go", "Zig"];
for lenguaje in lenguajes {
println!("Me gusta {lenguaje}");
}
}Podrías hacerlo con while y un índice, pero for es más corto y más seguro: no puedes equivocarte con el índice ni salirte del array.
Sin variable: Si no necesitas el valor de cada vuelta, usa
_como nombre:for _ in 0..3repite el bloque tres veces.
Etiquetas de bucle
Con bucles anidados, break y continue afectan al bucle más interno. Para salir de uno exterior, ponle una etiqueta: un nombre que empieza por comilla simple, seguido de dos puntos.
fn main() {
'externo: for fila in 1..=3 {
for columna in 1..=3 {
if fila * columna == 4 {
println!("Encontrado: {fila} × {columna} = 4");
break 'externo;
}
println!("{fila} × {columna}");
}
}
}break 'externo termina los dos bucles de golpe. Sin la etiqueta, solo saldría del bucle de columna y seguiría con la siguiente fila. También puedes usar continue 'externo.
¿Qué bucle elijo?
| Bucle | Úsalo cuando… |
|---|---|
for | Recorres un rango o un array. Es la opción por defecto |
while | Repites mientras se cumpla una condición |
loop | Repites hasta que ocurra algo dentro del bucle o quieres devolver un valor con break |
Hora de practicar
Ejercicios
0/5 resueltos
Reto 1 de 5 Resuelto
estado_bateria con if, else if y else: imprime Batería baja si nivel es menor que 20, Batería llena si es 100 y Batería normal en cualquier otro caso.Batería baja Batería llena Batería normal Batería normal
Al ejecutar, unos tests ocultos comprueban tus funciones.
Pulsa Ejecutar para compilar y ver aquí la salida de tu programa.