map para Result

El pánico en el multiplica del ejemplo anterior no crea un código robusto. Generalmente, queremos devolver el error a la persona que llama para que pueda decidir cuál es la forma correcta de responder a los errores.

Primero necesitamos saber con qué tipo de error estamos tratando. Para determinar el tipo de Err, usamos parse(), que se implementa con el rasgo FromStr para i32. Como resultado, el tipo Err se especifica como ParseIntError.

En el siguiente ejemplo, la sencilla declaración de match conduce a un código que en general es más engorroso.

use std::num::ParseIntError;

// Con el tipo de retorno reescrito, usamos la coincidencia de patrones sin `unwrap()`.
fn multiplica(primer_num_str: &str, segundo_num_str: &str) -> Result<i32, ParseIntError> {
    match primer_num_str.parse::<i32>() {
        Ok(primer_num)  => {
            match segundo_num_str.parse::<i32>() {
                Ok(segundo_num)  => {
                    Ok(primer_num * segundo_num)
                },
                Err(e) => Err(e),
            }
        },
        Err(e) => Err(e),
    }
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n es {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    // Esto todavía presenta una respuesta razonable.
    let veinte = multiplica("10", "2");
    print(veinte);

    // Lo siguiente ahora proporciona un mensaje de error mucho más útil.
    let tt = multiplica("t", "2");
    print(tt);
}

Afortunadamente, Options map, and_then, y muchos otros combinadores también se implementan para Result. Result contiene una lista completa.

use std::num::ParseIntError;

// Como con `Option`, podemos usar combinadores como `map()`.
// Esta función es por lo demás idéntica a la anterior y dice:
// Modifica n si el valor es válido, de lo contrario pasa el error.
fn multiplica(primer_num_str: &str, segundo_num_str: &str) -> Result<i32, ParseIntError> {
    primer_num_str.parse::<i32>().and_then(|primer_num| {
        segundo_num_str.parse::<i32>().map(|segundo_num| primer_num * segundo_num)
    })
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n es {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    // Esto todavía presenta una respuesta razonable.
    let veinte = multiplica("10", "2");
    print(veinte);

    // Lo siguiente ahora proporciona un mensaje de error mucho más útil.
    let tt = multiplica("t", "2");
    print(tt);
}