Rust’s error handling is elegant and type-safe. Here’s how to use it effectively.

Option Type

fn find_user(id: u32) -> Option<String> {
    if id > 0 {
        Some(format!("User {}", id))
    } else {
        None
    }
}

match find_user(1) {
    Some(name) => println!("Found: {}", name),
    None => println!("Not found"),
}

Result Type

use std::fs::File;

fn read_file(path: &str) -> Result<String, std::io::Error> {
    std::fs::read_to_string(path)
}

match read_file("data.txt") {
    Ok(content) => println!("Content: {}", content),
    Err(e) => println!("Error: {}", e),
}

Error Propagation

fn read_config() -> Result<String, std::io::Error> {
    let content = std::fs::read_to_string("config.txt")?;
    Ok(content)
}

Custom Errors

use std::fmt;

#[derive(Debug)]
struct CustomError {
    message: String,
}

impl fmt::Display for CustomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.message)
    }
}

Best Practices

  1. Use Result for recoverable errors
  2. Use Option for optional values
  3. Propagate errors with ?
  4. Create custom errors when needed
  5. Handle errors explicitly

Conclusion

Handle errors elegantly in Rust! 🦀