unwrap, unwrap_or, unwrap_or_default, unwrap_or_else

Result match unwrap unwrap_or unwrap_or_default unwrap_or_else

Out of the many ways to handle errors in Rust we have already seen unwrap, but it has a number of better alternatives that would avoid the panic! if there was an error.

In this example we have a string that we are trying to convert to u32 number using the parse method that returns a Result instance. This Result either contains

using match

Probably the most verbose way to handle a Result is by using match. Here if the operation succeeded the result will be in val and first block will be executed. If the operation fails we get back an Err that will be in the err variable.

match input.parse::<u32>() {
    Ok(val) => {
        println!("{}", val);
    },
    Err(err) => {
        eprintln!("Error: {}", err);
    }
};

unwrap, unwrap_or, unwrap_default, unwrap_or_else

With each method, if the operation succeeds we get back the result. They differ in the case when there is an error.

unwrap

let number = input.parse::<u32>().unwrap();

If the operation fails we get a panic!:

called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }

unwrap_or

let number = input.parse::<u32>().unwrap_or(23);

If the operation fails we get the value provided there. In this case the arbitrary value of 23.

unwrap_or_default

let number = input.parse::<u32>().unwrap_or_default();

If the operation fails we get back the default value of the expected type. For u32 it is 0.

unwrap_or_else

let number = input.parse::<u32>().unwrap_or_else(|err| {
    eprintln!("{}", err);
    12
});

If the operation fails Rust will call the provided function passing the error to it. The function can do anything and whatever it returns will be returned to the called. In our example it is 12.

The full example

examples/unwrap-or/src/main.rs

fn main() {
    using_match();

    //using_unwrap();
}

fn using_unwrap() {
    //let input = "42";
    let input = "42.2";


    //let number = input.parse::<u32>().unwrap();
    //let number = input.parse::<u32>().unwrap_or(23);
    //let number = input.parse::<u32>().unwrap_or_default();

    let number = input.parse::<u32>().unwrap_or_else(|err| {
        eprintln!("{}", err);
        12
    });
    // Will set the function returns.

    println!("number: {}", number);
}

fn using_match() {
    //let input = "42";
    let input = "42.2";

    match input.parse::<u32>() {
        Ok(val) => {
            println!("{}", val);
        },
        Err(err) => {
            eprintln!("Error: {}", err);
        }
    };
}

Conclusion

Which one you use will depend on the situation.

Related Pages

Rocket - access custom configuration in the routes