If Let y While Let en Rust
Ya usaste match para manejar Option y Result. Sin embargo, la mayoría de las veces solo te interesa un patrón y quieres ignorar todo lo demás. Escribir un match completo con una rama _ => {} que no hace nada funciona, pero es más ceremonia de la que hace falta. if let es el atajo.
El problema de usar un match completo aquí
Sección titulada «El problema de usar un match completo aquí»fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("La edad es {value}"), _ => {}, // este caso en realidad no nos interesa }}Ese _ => {} no hace nada, salvo cumplir la regla de match de que “hay que manejar todos los casos”. Si lo único que quieres es actuar cuando hay un Some, es más código del que la idea merece.
fn main() { let age: Option<i32> = Some(30);
if let Some(value) = age { println!("La edad es {value}"); }}Salida:
La edad es 30Léelo así: “si age encaja con el patrón Some(value), ejecuta este bloque, con value valiendo lo que había dentro”. Si age es None, el bloque simplemente se salta: sin errores y sin imprimir nada.
Añadir un else
Sección titulada «Añadir un else»if let puede llevar un else, igual que un if normal:
fn main() { let age: Option<i32> = None;
if let Some(value) = age { println!("La edad es {value}"); } else { println!("No se indicó la edad"); }}if let con Result
Sección titulada «if let con Result»Funciona igual con Result, que conociste en la página Result:
fn main() { let input = "42";
if let Ok(number) = input.parse::<i32>() { println!("Convertido: {number}"); } else { println!("No se pudo convertir"); }}Encadenar con else if let
Sección titulada «Encadenar con else if let»Igual que if tiene else if, después de un if let puede venir un else if let. Rust prueba cada patrón por orden y ejecuta el primer bloque que encaje. Es muy útil cuando tienes varios sitios donde buscar un valor, en orden de preferencia:
fn main() { let nickname: Option<&str> = None; let full_name: Option<&str> = Some("Ferris Crab");
if let Some(nick) = nickname { println!("¡Hola, {nick}!"); } else if let Some(name) = full_name { println!("Hola, {name}."); } else { println!("Hola, desconocido."); }}Salida:
Hola, Ferris Crab.nickname es None, así que el primer bloque se salta. full_name encaja con Some(name), así que se ejecuta ese bloque, y el else final nunca se alcanza. También puedes meter una condición normal, como else if is_admin { ... }, en cualquier punto de la cadena.
Cada variable solo existe dentro de su propio bloque: nick no se puede usar en el segundo bloque, y name no se puede usar cuando termina la cadena. Si necesitas el valor desempaquetado para el resto de tu código, mira let-else en la página de Coincidencia de patrones.
while let
Sección titulada «while let»while let aplica la misma idea a un bucle: sigue repitiendo mientras un valor encaje con un patrón. Es especialmente práctico para ir vaciando una colección:
fn main() { let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { println!("{top}"); }}Salida:
321.pop() devuelve Some(valor) mientras quede algo, y None cuando el vector está vacío; en ese momento, while let detiene el bucle automáticamente. No hace falta comprobar la longitud a mano.
if let o match: cuál usar
Sección titulada «if let o match: cuál usar»Usa match cuando de verdad necesites manejar varios casos de forma distinta. Recurre a if let cuando solo te importe un patrón y todo lo demás deba ignorarse. No sustituye a match: es solo una forma más corta de escribir el caso habitual de “solo me importa una rama”.
Práctica
Sección titulada «Práctica»1. Sumar una pila
Sección titulada «1. Sumar una pila»Empieza con let mut numbers = vec![4, 8, 15]; y un total acumulado de 0. Usa while let con .pop() para sacar los números del final de uno en uno, súmalos a total e imprime el número y el nuevo total. Pista: total necesita mut, y total += n le suma un valor.
Ver solución
fn main() { let mut numbers = vec![4, 8, 15]; let mut total = 0;
while let Some(n) = numbers.pop() { total += n; println!("saqué {n}, el total ahora es {total}"); }}Salida:
saqué 15, el total ahora es 15saqué 8, el total ahora es 23saqué 4, el total ahora es 27.pop() saca del final, por eso el 15 sale primero.
2. Comprobar una edad escrita como texto
Sección titulada «2. Comprobar una edad escrita como texto»Guarda let input = "17";. Si se puede convertir a u32, imprime si esa edad es de un adulto (18 o más) o de un menor. Si no se puede convertir, imprime que no es un número. Prueba también a cambiar input por "abc". Pista: pon un if / else normal dentro del bloque if let.
Ver solución
fn main() { let input = "17";
if let Ok(age) = input.parse::<u32>() { if age >= 18 { println!("{age}: es adulto"); } else { println!("{age}: es menor de edad"); } } else { println!("'{input}' no es un número"); }}Salida:
17: es menor de edadCon input = "abc", la conversión falla, se ejecuta el else de fuera y se imprime 'abc' no es un número.
Resumen
Sección titulada «Resumen»if let Patrón = valor { ... }ejecuta el bloque solo sivalorencaja conPatrón; todo lo demás se salta sin avisar.- Añade
elsepara manejar el caso que no encaja, igual que en unifnormal, y encadena varios patrones conelse if let. while let Patrón = valor { ... }repite el bucle mientras el valor siga encajando; es útil para vaciar una colección con.pop().- Usa
if let/while letcuando solo te importa un patrón; usamatchcuando necesitas manejar varios casos por separado.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»Comprueba lo aprendido
1. ¿Qué pasa cuando se ejecuta if let Some(value) = age y age es None?
2. ¿Cuándo conviene usar match en lugar de if let?
3. En while let Some(top) = stack.pop() { ... }, ¿cuándo se detiene el bucle?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- Control de flujo conciso con if let y let…else — El libro de Rust (en inglés): la introducción oficial, que también explica let-else.
- if let — Rust by Example (en inglés): ejemplos ejecutables con
Optiony con tus propios enums, y por quéif letes mejor quematchpara un solo patrón. - while let — Rust by Example (en inglés): un bucle reescrito de
loop+matcha unwhile letmás corto. - Patrones
if let— The Rust Reference (en inglés): las reglas exactas, incluida la relación entreif letymatch.