Result::unwrap() / expect() / ? Operator
| Since: | Rust 1.0(2015) |
|---|
Methods for extracting values from Result, and the ? operator for automatically propagating errors to the caller. The ? operator in particular can significantly reduce error-handling boilerplate.
Syntax
let value = result.unwrap();
// Panics with the specified message if Err.
let value = result.expect("error message");
let value = result.unwrap_or(default_value);
// Propagates the error to the caller if Err (the ? operator).
// Can only be used inside a function that returns Result.
let value = some_func()?;
Method List
| Method / Operator | Description |
|---|---|
| unwrap() | Returns x if the value is Ok(x), or panics if it is Err. Using this outside of prototypes and test code carries a risk of panic. |
| expect("msg") | Same as unwrap(), but displays the specified message on panic. Makes it easier to identify the cause of the error. |
| unwrap_or(val) | Returns the default value if the result is Err. Use this when you want to ignore the error and continue processing. |
| unwrap_or_else(fn) | Runs a closure that receives the error value when the result is Err(e). You can return a default value based on the error's content. |
| ? operator | Returns x if the value is Ok(x), or immediately returns the error to the caller if it is Err(e). Can only be used in functions that return Result (or Option). |
| ok() / err() | Converts a Result into an Option. ok() converts Ok(x) to Some(x) and Err to None. |
Sample Code
sample_result_unwrap_question.rs
use std::num::ParseIntError;
// Propagates errors to the caller using the ? operator.
fn parse_and_double(s: &str) -> Result<i32, ParseIntError> {
let n = s.parse::<i32>()?; // Returns Err immediately if parsing fails.
Ok(n * 2)
}
// Example of chaining multiple ? operators.
fn parse_sum(a: &str, b: &str) -> Result<i32, ParseIntError> {
let x = a.parse::<i32>()?;
let y = b.parse::<i32>()?;
Ok(x + y)
}
fn main() {
// Calling functions that use the ? operator.
println!("{:?}", parse_and_double("5")); // Ok(10)
println!("{:?}", parse_and_double("abc")); // Err(...)
println!("{:?}", parse_sum("3", "4")); // Ok(7)
println!("{:?}", parse_sum("3", "x")); // Err(...)
// Using unwrap_or to fall back to a default value on error.
let n = "abc".parse::<i32>().unwrap_or(0);
println!("{}", n); // 0
// Using unwrap_or_else to handle the error value.
let n = "abc".parse::<i32>().unwrap_or_else(|e| {
println!("Parse error: {}", e);
-1
});
println!("{}", n); // -1
// Converting a Result to an Option with ok().
let opt = "42".parse::<i32>().ok();
println!("{:?}", opt); // Some(42)
}
Compile with the following command:
rustc result_unwrap_question.rs
./result_unwrap_question
Ok(10)
Err(ParseIntError { kind: InvalidDigit })
Ok(7)
Err(ParseIntError { kind: InvalidDigit })
0
Parse error: invalid digit found in string
-1
Some(42)
Common Mistakes
Mistake 1: Using ? in a function with a void return type causes a compile error
The ? operator requires the function's return type to be Result (or Option). To use ? in main(), change its return type to Result<(), Box<dyn std::error::Error>>.
unwrap_mistake1.rs
use std::num::ParseIntError;
// ? cannot be used in a function that returns ().
fn parse_number(s: &str) {
let n = s.parse::<i32>()?; // compile error
println!("{}", n);
}
fn main() {
parse_number("42");
}
Compile with the following command:
rustc unwrap_mistake1.rs error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option`
Change the function to return a Result type, or use match instead of ?.
unwrap_fix1.rs
use std::num::ParseIntError;
fn parse_number(s: &str) -> Result<(), ParseIntError> {
let n = s.parse::<i32>()?;
println!("{}", n);
Ok(())
}
// To use ? in main, change its return type to Result.
fn main() -> Result<(), Box<dyn std::error::Error>> {
parse_number("42")?;
parse_number("99")?;
Ok(())
}
Compile with the following command:
rustc unwrap_fix1.rs ./unwrap_fix1 42 99
Mistake 2: A vague expect() message makes debugging difficult
When using expect(), provide a specific message that will help with debugging if a panic occurs. A vague message like "should succeed" makes it hard to identify the cause.
unwrap_expect.rs
use std::env;
fn main() {
// A vague message makes debugging difficult.
// let port = env::var("PORT").expect("should succeed");
// Provide a specific message, or use a fallback instead.
let port = env::var("PORT").unwrap_or_else(|_| String::from("8080"));
println!("PORT={}", port);
// In test code, a clear expect() message is useful.
let n = "42".parse::<i32>().expect("this is a compile-time constant and cannot fail to parse");
println!("n={}", n);
}
Compile with the following command:
rustc unwrap_expect.rs ./unwrap_expect PORT=8080 n=42
Notes
The ? operator is syntactic sugar introduced in Rust 1.13 that reduces manual error-propagation code using match to a single character. The ? operator can only be used when the function's return type is Result or Option. To use it in main(), you must change the return type to Result<(), Box<dyn std::error::Error>>.
When error type conversion is needed, ? automatically calls the From trait to convert the error type. If your custom error type has the appropriate From implementation, you can use ? consistently even in functions that mix different error types.
If you find any errors or copyright issues, please contact us.