unwrap_or() and Related Methods
unwrap_or(), unwrap_or_else(), and unwrap_or_default() are non-panicking extraction methods on Option<T> and Result<T, E>. They return the inner value T when the receiver is Some(T) or Ok(T), and substitute a fallback value of type T when the receiver is None or Err(E).
Fallback Extraction Methods Compared
Option<T> / Result<T, E>
├── Some(v) / Ok(v) ──> returns v
└── None / Err(e) ──┬── unwrap_or(fallback) --> returns `fallback` (evaluated eagerly)
├── unwrap_or_else(f) --> calls `f()` or `f(e)` (evaluated lazily)
└── unwrap_or_default() --> returns `T::default()`
| Method | Evaluation Timing | Bounds Required | Best Used When |
|---|---|---|---|
unwrap_or(default) |
Eager: default is evaluated before the method runs |
None | default is a cheap literal or already-computed variable (0, "", true) |
unwrap_or_else(f) |
Lazy: closure f runs only on None or Err(e) |
FnOnce() -> T (Option) or FnOnce(E) -> T (Result) |
Computing the fallback allocates memory, does I/O, or logs the error e |
unwrap_or_default() |
Lazy: T::default() runs only on None or Err(e) |
T: Default |
The natural fallback is T's zero/empty value (0, "", Vec::new()) |
Constant Fallbacks with unwrap_or()
Use unwrap_or(val) when the fallback is a constant or trivial expression that does not allocate:
fn main() {
let custom_port: Option<u16> = None;
let configured_port: Option<u16> = Some(9000);
println!("Port A: {}", custom_port.unwrap_or(8080));
println!("Port B: {}", configured_port.unwrap_or(8080));
let parsed: Result<i32, _> = "invalid".parse();
println!("Parsed count: {}", parsed.unwrap_or(-1));
}
Port A: 8080
Port B: 9000
Parsed count: -1
Lazy Fallbacks with unwrap_or_else()
Because function arguments in Rust are evaluated before the function is called, passing String::from("fallback") to unwrap_or(...) allocates a String even when the Option is Some. Passing a closure to unwrap_or_else(...) avoids the work on the success path and gives Result access to the error E:
fn expensive_default(reason: &str) -> String {
println!(" [computing fallback because of: {reason}]");
String::from("guest_session")
}
fn main() {
let active: Result<String, &str> = Ok(String::from("admin_session"));
let expired: Result<String, &str> = Err("token expired");
let s1 = active.unwrap_or_else(expensive_default);
println!("s1 = {s1}");
let s2 = expired.unwrap_or_else(expensive_default);
println!("s2 = {s2}");
}
s1 = admin_session
[computing fallback because of: token expired]
s2 = guest_session
Type-Default Fallbacks with unwrap_or_default()
For any type T that implements std::default::Default (numbers default to 0, bool to false, String to "", Vec<U> to [], Option<U> to None), unwrap_or_default() returns T::default() on None or Err:
fn main() {
let missing_name: Option<String> = None;
let bad_number: Result<u32, _> = "NaN".parse();
let missing_items: Option<Vec<i32>> = None;
println!("name: {:?}", missing_name.unwrap_or_default());
println!("num: {}", bad_number.unwrap_or_default());
println!("items: {:?}", missing_items.unwrap_or_default());
}
name: ""
num: 0
items: []