A menudo, un simple if
/else
no es suficiente, debido a que tienes mas de dos opciones posibles. También, las condiciones pueden ser complejas. Rust posee una palabra reservada, match
, que te permite reemplazar construcciones if
/else
complicadas con algo mas poderoso. Echa un vistazo:
let x = 5; match x { 1 => println!("uno"), 2 => println!("dos"), 3 => println!("trees"), 4 => println!("cuatro"), 5 => println!("cinco"), _ => println!("otra cosa"), }
match
toma una expresión y luego bifurca basado en su valor. Cada brazo
de la rama tiene la forma valor => expresión
. Cuando el valor coincide, la expresión del brazo es evaluada. Es llamado match
por el termino ‘pattern matching’, del cual match
es una implementación. Hay una sección entera acerca de los patrones que cubre todos los patrones posibles.
Entonces, cual es la gran ventaja? Bueno, hay unas pocas. Primero que todo, match
impone chequeo de agotamiento
(‘exhaustiveness checking’). Ves el ultimo brazo, el que posee el guión bajo (_
)? Si removemos ese brazo, Rust nos proporcionara un error:
error: non-exhaustive patterns: `_` not covered
En otras palabras, Rust esta tratando de decirnos que olvidamos un valor. Debido a que x
es un entero, Rust sabe que x
puede tener un numero de valores diferentes - por ejemplo, 6
. Sin el _
, sin embargo, no hay brazo que pueda coincidir, y en consecuencia Rust se rehusa a compilar el código. _
actúa como un ‘brazo que atrapa todo’. Si ninguno de los otros brazos coincide, el brazo con el _
lo hará, y puesto que tenemos dicho ‘brazo que atrapa todo’, tenemos ahora un brazo para cada valor posible de x
, y como resultado, nuestro programa compilara satisfactoriamente.
match
es también una expresión, lo que significa que lo podemos usar en el lado derecho de un let
o directamente en donde una expresión sea usada:
let x = 5; let number = match x { 1 => "uno", 2 => "dos", 3 => "tres", 4 => "cuatro", 5 => "cinco", _ => "otra cosa", };
Algunas veces es una buena forma de convertir algo de un tipo a otro.
match
en enumsOtro uso importante de la palabra reservada match
es para procesar las posibles variantes de una enum:
enum Mensaje { Salir, CambiarColor(i32, i32, i32), Mover { x: i32, y: i32 }, Escribir(String), } fn salir() { /* ... */ } fn cambiar_color(r: i32, g: i32, b: i32) { /* ... */ } fn mover_cursor(x: i32, y: i32) { /* ... */ } fn procesar_mensaje(msj: Mensaje) { match msj { Mensaje::Salir => salir(), Mensaje::CambiarColor(r, g, b) => cambiar_color(r, g, b), Mensaje::Mover { x: x, y: y } => mover_cursor(x, y), Mensaje::Escribir(s) => println!("{}", s), }; }
Otra vez, el compilador de Rust chequea agotamiento, demandando que tengas un brazo para cada variante de la enumeración. Si dejas uno por fuera, Rust generara un error en tiempo de compilación, a menos que uses _
.
A diferencia de los usos previos de match
, no puedes usar de la sentencia if
para hacer esto. Puedes hacer uso de una sentencia if let
que puede ser vista como una forma abreviada de match
.