- If an
Option
type hasSome
value or aResult
type has aOk
value, the value inside them passes to the next step. - If the
Option
type hasNone
value or theResult
type hasErr
value, program panics; IfErr
, 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.
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
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
💡 These are bit similar to
unwrap()
, If anOption
type hasSome
value or aResult
type has aOk
value, the value inside them passes to the next step. But when havingNone
orErr
, the functionalities are bit different.
unwrap_or()
: WithNone
orErr
, the value you passes tounwrap_or()
is passing to the next step. But the data type of the value you passes should match with the data type of the relevantSome
orOk
.
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()
: WithNone
orErr
, the default value of the data type of the relevantSome
orOk
, 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 tounwrap_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 relevantSome
orOk
.
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
}