Result

Result es una versión más rica del tipo Option que describe un posible error en lugar de una posible ausencia.

Es decir, Result<T,E> podría tener uno de dos resultados:

  • Ok(T): Se encontró un elemento T
  • Err(E): Se encontró un error con el elemento E

Por convención, el resultado esperado es Ok mientras que el resultado inesperado es Err.

Como Option, Result tiene muchos métodos asociados. unwrap(), por ejemplo, produce el elemento T o panics. Para el manejo de casos, hay muchos combinadores entre Result y Option que se superponen.

Al trabajar con Rust, es probable que encuentres métodos que devuelvan el tipo Result, como el método parse(). Puede que no siempre sea posible analizar una cadena en el otro tipo, por lo que parse() devuelve un Result que indica un posible error.

Veamos qué sucede cuando parse() una cadena con éxito y sin éxito:

fn multiplica(primer_num_str: &str, segundo_num_str: &str) -> i32 {
    // Intentemos usar `unwrap()` para obtener el número. ¿Funcionará?
    let primer_num = primer_num_str.parse::<i32>().unwrap();
    let segundo_num = segundo_num_str.parse::<i32>().unwrap();
    primer_num * segundo_num
}

fn main() {
    let veinte = multiplica("10", "2");
    println!("producto es {}", veinte);

    let tt = multiplica("t", "2");
    println!("producto es {}", tt);
}

En el caso fallido, parse() nos deja con un error para que unwrap() entre en pánico. Además, el panic sale de nuestro programa y proporciona un mensaje de error desagradable.

Para mejorar la calidad de nuestro mensaje de error, debemos ser más específicos sobre el tipo de devolución y considerar el manejo explícito del error.

Usar Result en main

El tipo Result también puede ser el tipo de retorno de la función main si se especifica explícitamente. Normalmente, la función main tendrá la forma:

fn main() {
    println!("¡Hola Mundo!");
}

Sin embargo, main también puede tener un tipo de retorno de Result. Si ocurre un error dentro de la función main, devolverá un código de error e imprimirá una representación de depuración del error (usando el rasgo Debug). El siguiente ejemplo muestra un escenario de este tipo y toca los aspectos cubiertos en la siguiente sección.

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let numero_str = "10";
    let numero = match numero_str.parse::<i32>() {
        Ok(numero)  => numero,
        Err(e) => return Err(e),
    };
    println!("{}", numero);
    Ok(())
}