Result Type
Using the Result<T, E> enum for error handling.
Intermediate⏱️ 35 min📚 Prerequisites: 1
Result Type
The Result<T, E> is an enum used for error handling. It has two variants: Ok(T) (success) and Err(E) (error).
Result Definition
RUSTenum Result<T, E> { Ok(T), Err(E), }
Basic Usage
RUSTuse std::fs::File; let f = File::open("hello.txt"); match f { Ok(file) => println!("File opened"), Err(error) => println!("Error: {:?}", error), }
unwrap() and expect()
RUSTlet f = File::open("hello.txt").unwrap(); // Panic if error let f = File::open("hello.txt").expect("Failed to open");
unwrap_or_else()
RUSTlet f = File::open("hello.txt").unwrap_or_else(|error| { panic!("File opening error: {:?}", error); });
Propagating Errors (?) Operator
RUSTfn read_username_from_file() -> Result<String, io::Error> { let mut f = File::open("hello.txt")?; let mut s = String::new(); f.read_to_string(&mut s)?; Ok(s) }
The ? operator automatically propagates the error if Err, or unwraps the Ok value.
Code Examples
Basic Result
Using Result
RUST
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {
if denominator == 0.0 {
Err(String::from("Division by zero!"))
} else {
Ok(numerator / denominator)
}
}
fn main() {
match divide(10.0, 2.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
match divide(10.0, 0.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}Explanation:
Result allows us to explicitly handle errors. Ok contains the successful result, Err contains the error.
Unwrap Methods
Extracting Result values
RUST
fn safe_divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
fn main() {
let result1 = safe_divide(10.0, 2.0).unwrap_or(0.0);
println!("Result: {}", result1);
let result2 = safe_divide(10.0, 2.0).expect("Division failed");
println!("Result: {}", result2);
}Explanation:
unwrap_or safely returns a value, or the default if there's an error. expect panics if there's an error.
? Operator
Propagating errors with the ? operator
RUST
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
return Err(String::from("Division by zero"));
}
Ok(a / b)
}
fn calculate(a: f64, b: f64, c: f64) -> Result<f64, String> {
let result1 = divide(a, b)?;
let result2 = divide(result1, c)?;
Ok(result2)
}
fn main() {
match calculate(20.0, 2.0, 5.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}Explanation:
The ? operator automatically propagates the error if Result::Err, or unwraps the value if Result::Ok. This results in concise code.
Exercises
Result Function
Write a function that returns a Result!
Starter Code:
RUST
fn main() {
match parse_number("42") {
Ok(num) => println!("Number: {}", num),
Err(e) => println!("Error: {}", e),
}
}