Varios tipos de errores

Los ejemplos anteriores siempre han sido muy convenientes; Los Results interactúan con otros Results y las Options interactúan con otras Options.

A veces, una Opción necesita interactuar con un Result, o un Result<T, Error1> necesita interactuar con un Result<T, Error2>. En esos casos, queremos administrar nuestros diferentes tipos de errores de una manera que los haga componibles y fáciles de interactuar.

En el siguiente código, dos instancias de unwrap generan diferentes tipos de error. Vec::first devuelve una Option, mientras que parse::<i32> devuelve un Result<i32, ParseIntError>:

fn duplica_primer_elemento(vec: Vec<&str>) -> i32 {
    let first = vec.first().unwrap(); // Genera error 1
    2 * first.parse::<i32>().unwrap() // Genera error 2
}

fn main() {
    let numeros = vec!["42", "93", "18"];
    let vacio = vec![];
    let cadenas = vec!["tofu", "93", "18"];

    println!("El doble del primer elemento es {}", duplica_primer_elemento(numeros));

    println!("El doble del primer elemento es {}", duplica_primer_elemento(vacio));
    // Error 1: el vector de entrada está vacío

    println!("El doble del primer elemento es {}", duplica_primer_elemento(cadenas));
    // Error 2: el elemento no se analiza a un número
}

En las siguientes secciones, veremos varias estrategias para manejar este tipo de problemas.