Option y unwrap

En el último ejemplo, mostramos que podemos inducir fallos en el programa a voluntad. Le dijimos a nuestro programa que entrara en panic si la realeza recibía un regalo inapropiado: una serpiente. Pero, ¿y si la realeza esperaba un regalo y no lo recibió? Ese caso sería igual de malo, ¡así que hay que manejarlo!

Podríamos probar esto contra la cadena nula ("") como lo hacemos con una serpiente. Ya que estamos usando Rust, hagamos que el compilador señale los casos en los que no hay ningún regalo.

Una enum llamada Option<T> en la biblioteca std se usa cuando la ausencia es una posibilidad. Se manifiesta como una de dos "opciones":

  • Some(T): Se encontró un elemento de tipo T
  • None: No se encontró ningún elemento

Estos casos pueden manejarse explícitamente a través de match o implícitamente con unwrap. El manejo implícito devolverá el elemento interno o panic.

Ten en cuenta que es posible personalizar manualmente panic con expect, pero unwrap nos deja con una salida menos significativa que el manejo explícito. En el siguiente ejemplo, el manejo explícito produce un resultado más controlado al tiempo que conserva la opción de panic si se desea.

// El plebeyo lo ha visto todo y puede manejar bien cualquier regalo.
// Todos los obsequios se manejan explícitamente usando `match`.
fn da_a_plebeyo(regalo: Option<&str>) {
    // Especifica un curso de acción para cada caso.
    match regalo {
        Some("serpiente") => println!("¡Qué asco! Estoy devolviendo esta serpiente al bosque."),
        Some(inner)   => println!("̉¿{}? Que lindo.", inner),
        None          => println!("¿Sin regalo? Bueno."),
    }
}

// Nuestro protegido real entrará en `panic` al ver serpientes.
// Todos los regalos se manejan implícitamente usando `unwrap`.
fn da_a_protegido(regalo: Option<&str>) {
    // `unwrap` devuelve un `panic` cuando recibe un `None`.
    let interior = regalo.unwrap();
    if interior == "serpiente" { panic!("AAAaaaaa!!!!"); }

    println!("¡Amo los {}s!", interior);
}

fn main() {
    let food  = Some("repollo");
    let serpiente = Some("serpiente");
    let void  = None;

    da_a_plebeyo(food);
    da_a_plebeyo(serpiente);
    da_a_plebeyo(void);

    let pajaro = Some("petirrojo");
    let nothing = None;

    da_a_protegido(pajaro);
    da_a_protegido(nothing);
}