Unwrap and Expect

unwrap()

  • If an Option type has Some value or a Result type has a Ok value, the value inside them passes to the next step.
  • If the Option type has None value or the Result type has Err value, program panics; If Err, panics with the error message.

The functionality is bit similar to the following codes, which are using match instead unwrap().

Example with Option and match, before using unwrap()

fn main() {
    let x;
    match get_an_optional_value() {
        Some(v) => x = v, // if Some("abc"), set x to "abc"
        None => panic!(), // if None, panic without any message
    }

    println!("{}", x); // "abc" ; if you change line 14 `false` to `true`
}

fn get_an_optional_value() -> Option<&'static str> {

    //if the optional value is not empty
    if false {
        return Some("abc");
    }

    //else
    None
}


// --------------- Compile-time error ---------------
thread 'main' panicked at 'explicit panic', src/main.rs:5:17

Example with Result and match, before using unwrap()

fn main() {
    let x;
    match function_with_error() {
        Ok(v) => x = v, // if Ok(255), set x to 255
        Err(e) => panic!(e), // if Err("some message"), panic with error message "some message"
    }

    println!("{}", x); // 255 ; if you change line 13 `true` to `false`
}

fn function_with_error() -> Result<u64, String> {
    //if error happens
    if true {
        return Err("some message".to_string());
    }

    // else, return valid output
    Ok(255)
}


// ---------- Compile-time error ----------
thread 'main' panicked at 'some message', src/main.rs:5:19

Same codes in above main functions can be written with unwrap() using two lines.

// 01. unwrap error message for None
fn main() {
    let x = get_an_optional_value().unwrap();

    println!("{}", x);
}

// --------------- Compile-time error ---------------
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', libcore/option.rs:345:21


// 02. unwrap error message for Err
fn main() {
    let x = function_with_error().unwrap();

    println!("{}", x);
}

// --------------- Compile-time error ---------------
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "some message"', libcore/result.rs:945:5

⭐ But as you can see, when using unwrap() error messages are not showing the exact line numbers where the panic happens.

expect()

Similar to unwrap() but can set a custom message for the panics.

// 01. expect error message for None
fn main() {
    let n: Option<i8> = None;

    n.expect("empty value returned");
}

// --------------- Compile-time error ---------------
thread 'main' panicked at 'empty value returned', libcore/option.rs:989:5


// 02. expect error message for Err
fn main() {
    let e: Result<i8, &str> = Err("some message");

    e.expect("expect error message");
}

// --------------- Compile-time error ---------------
thread 'main' panicked at 'expect error message: "some message"', libcore/result.rs:945:5

unwrap_err() and expect_err() for Result types

The opposite case of unwrap() and expect(); Panics with Ok values, instead Err. Both print the value inside Ok on the error message.

💡 Usually use with tests.

// 01. unwrap_err error message for Ok
fn main() {
    let o: Result<i8, &str> = Ok(8);

    o.unwrap_err();
}

// ---------- Compile-time error ----------
thread 'main' panicked at 'called `Result::unwrap_err()` on an `Ok` value: 8', libcore/result.rs:945:5


// 02. expect_err error message for Ok
fn main() {
    let o: Result<i8, &str> = Ok(8);

    o.expect_err("Should not get Ok value");
}

// ---------- Compile-time error ----------
thread 'main' panicked at 'Should not get Ok value: 8', libcore/result.rs:945:5

unwrap_or(), unwrap_or_default() and unwrap_or_else()

💡 These are bit similar to unwrap(), If an Option type has Some value or a Result type has a Ok value, the value inside them passes to the next step. But when having None or Err, the functionalities are bit different.

  • unwrap_or() : With None or Err, the value you passes to unwrap_or() is passing to the next step. But the data type of the value you passes should match with the data type of the relevant Some or Ok.
fn main() {
    let v1 = 8;
    let v2 = 16;

    let s_v1 = Some(8);
    let n = None;

    assert_eq!(s_v1.unwrap_or(v2), v1); // Some(v1) unwrap_or v2 = v1
    assert_eq!(n.unwrap_or(v2), v2);    // None unwrap_or v2 = v2

    let o_v1: Result<i8, &str> = Ok(8);
    let e: Result<i8, &str> = Err("error");

    assert_eq!(o_v1.unwrap_or(v2), v1); // Ok(v1) unwrap_or v2 = v1
    assert_eq!(e.unwrap_or(v2), v2);    // Err unwrap_or v2 = v2
}
  • unwrap_or_default() : With None or Err, the default value of the data type of the relevant Some or Ok, is passing to the next step.
fn main() {
    let v = 8;
    let v_default = 0;

    let s_v: Option<i8> = Some(8);
    let n: Option<i8> = None;

    assert_eq!(s_v.unwrap_or_default(), v);       // Some(v) unwrap_or_default = v
    assert_eq!(n.unwrap_or_default(), v_default); // None unwrap_or_default = default value of v

    let o_v: Result<i8, &str> = Ok(8);
    let e: Result<i8, &str> = Err("error");

    assert_eq!(o_v.unwrap_or_default(), v);       // Ok(v) unwrap_or_default = v
    assert_eq!(e.unwrap_or_default(), v_default); // Err unwrap_or_default = default value of v
}
  • unwrap_or_else() : Similar to unwrap_or(). The only difference is, instead of passing a value, you have to pass a closure which returns a value with the same data type of the relevant Some or Ok.
fn main() {
    let v1 = 8;
    let v2 = 16;

    let s_v1 = Some(8);
    let n = None;
    let fn_v2_for_option = || 16;

    assert_eq!(s_v1.unwrap_or_else(fn_v2_for_option), v1); // Some(v1) unwrap_or_else fn_v2 = v1
    assert_eq!(n.unwrap_or_else(fn_v2_for_option), v2);    // None unwrap_or_else fn_v2 = v2

    let o_v1: Result<i8, &str> = Ok(8);
    let e: Result<i8, &str> = Err("error");
    let fn_v2_for_result = |_| 16;

    assert_eq!(o_v1.unwrap_or_else(fn_v2_for_result), v1); // Ok(v1) unwrap_or_else fn_v2 = v1
    assert_eq!(e.unwrap_or_else(fn_v2_for_result), v2);    // Err unwrap_or_else fn_v2 = v2
}