What are error handling best practices

Use Result for recoverable errors with the ? operator and panic! only for unrecoverable failures in Rust.

Use Result<T, E> for recoverable errors and panic! only for unrecoverable ones.

use std::fs::File;
use std::io::ErrorKind;

fn read_file(path: &str) -> Result<String, std::io::Error> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    match read_file("hello.txt") {
        Ok(content) => println!("{content}"),
        Err(e) if e.kind() == ErrorKind::NotFound => println!("File not found"),
        Err(e) => panic!("Unexpected error: {e}"),
    }
}

The ? operator propagates errors automatically, while match lets you handle specific cases like NotFound before panicking on unexpected failures.