Option<T> and Result<T, E> in Depth
unwrap_or_default()
The .unwrap_or_default() method on Option<T> and Result<T, E> extracts the contained Some(v) or Ok(v) value, or returns T::default() (Default::default()) if the value is None or Err(_).
Signatures and Fallback Family Comparison
impl<T: Default> Option<T> {
pub fn unwrap_or_default(self) -> T;
}
impl<T: Default, E> Result<T, E> {
pub fn unwrap_or_default(self) -> T;
}
| Method | Fallback Source | Evaluation | Panics? |
|---|---|---|---|
x.unwrap() |
None | — | Yes (on None / Err) |
x.expect("msg") |
None | — | Yes (with custom message) |
x.unwrap_or(fallback) |
Explicit fallback: T argument |
Eager (fallback always evaluated) |
No |
x.unwrap_or_else(f) |
Closure f() (FnOnce() -> T or FnOnce(E) -> T) |
Lazy (runs only on None / Err) |
No |
x.unwrap_or_default() |
T::default() (T: Default) |
Lazy (calls T::default() only on None / Err) |
No |
Using unwrap_or_default() on Option<T> and Result<T, E>
Because T::default() is 0 for numbers, false for bool, "" (empty, non-allocating String) for String, and [] (empty, non-allocating Vec) for Vec<T>, .unwrap_or_default() eliminates boilerplate fallback literals:
fn main() {
// 1. On Option<String> -> returns empty String "" on None:
let present_name: Option<String> = Some(String::from("Alice"));
let missing_name: Option<String> = None;
println!("Present: {:?}", present_name.unwrap_or_default());
println!("Missing: {:?}", missing_name.unwrap_or_default());
// 2. On Result<u32, ParseIntError> -> returns 0 on Err:
let valid_count: u32 = "42".parse().unwrap_or_default();
let bad_count: u32 = "not_a_number".parse().unwrap_or_default();
println!("Valid count: {valid_count}, Bad count: {bad_count}");
}
Present: "Alice"
Missing: ""
Valid count: 42, Bad count: 0
Taking Ownership From &mut Option<T> Using Option::take()
A closely related Default-based operation on Option<T> itself is opt.take() (equivalent to std::mem::take(&mut opt) since Option::<T>::default() is None): it moves the inner Some(v) out of a &mut Option<T> and leaves None in its place in $O(1)$ time without requiring T: Default or T: Clone:
struct Worker {
active_task: Option<String>,
}
impl Worker {
fn finish_task(&mut self) -> String {
// Moves `Some(task)` out of `self.active_task` (leaving `None`),
// or returns `""` via `unwrap_or_default()` if no task was active:
self.active_task.take().unwrap_or_default()
}
}
fn main() {
let mut w = Worker {
active_task: Some(String::from("reindex_db")),
};
println!("1st finish: {:?}", w.finish_task());
println!("2nd finish: {:?}", w.finish_task());
}
1st finish: "reindex_db"
2nd finish: ""