Core Concepts
Error Handling
Handle errors gracefully with Rust's Result type, the ? operator, and custom error types.
Result in Rust
Rust has no exceptions. Errors are values returned as Result<T, E>:
Ok(value)— successErr(error)— failure
The ? Operator
The ? operator propagates errors automatically. If Ok, unwraps the value. If Err, returns the error from the current function.
Custom Error Types
Define your own error types for rich error information. Implement the std::error::Error trait.
Libraries
thiserror: Easy custom error typesanyhow: Flexible error handling for applications
Example
rust
use std::fs::File;
use std::io::{self, Read};
use std::num::ParseIntError;
// Custom error type
#[derive(Debug)]
enum AppError {
Io(io::Error),
Parse(ParseIntError),
Custom(String),
}
impl From<io::Error> for AppError {
fn from(e: io::Error) -> Self { AppError::Io(e) }
}
impl From<ParseIntError> for AppError {
fn from(e: ParseIntError) -> Self { AppError::Parse(e) }
}
// ? operator propagates errors
fn read_number_from_file(path: &str) -> Result<i32, AppError> {
let mut file = File::open(path)?; // ? converts io::Error to AppError
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let num: i32 = contents.trim().parse()?; // ? converts ParseIntError
Ok(num)
}
// Chaining with combinators
fn double_first(numbers: &[i32]) -> Result<i32, AppError> {
let first = numbers.first()
.ok_or_else(|| AppError::Custom("empty list".to_string()))?;
Ok(first * 2)
}
fn main() {
// match on Result
match read_number_from_file("number.txt") {
Ok(n) => println!("Got number: {}", n),
Err(AppError::Io(e)) => println!("IO error: {}", e),
Err(AppError::Parse(e)) => println!("Parse error: {}", e),
Err(AppError::Custom(msg)) => println!("Error: {}", msg),
}
// unwrap_or_else for default
let n = read_number_from_file("missing.txt").unwrap_or(0);
println!("Number or default: {}", n);
// map transforms Ok value
let doubled = read_number_from_file("number.txt").map(|n| n * 2);
// Result with vectors
let strings = vec!["1", "2", "three", "4"];
let numbers: Result<Vec<i32>, _> = strings.iter()
.map(|s| s.parse::<i32>())
.collect();
println!("{:?}", numbers); // Err(...)
}Try it yourself — RUST