Q: How do you handle errors in Rust?

Answer:

Rust groups errors into two major categories: Recoverable and Unrecoverable errors.

1. Recoverable Errors (Result<T, E>)

For errors that can be handled gracefully (like a file not being found), Rust uses the Result enum:

#![allow(unused)]
fn main() {
enum Result<T, E> {
    Ok(T),
    Err(E),
}
}

You can handle Result using match or the ? operator.

Using match:

#![allow(unused)]
fn main() {
use std::fs::File;

let f = File::open("hello.txt");
let f = match f {
    Ok(file) => file,
    Err(error) => panic!("Problem opening the file: {:?}", error),
};
}

Using the ? Operator: The ? operator is a shorthand that unwraps Ok values or immediately returns the Err from the current function.

#![allow(unused)]
fn main() {
use std::fs::File;
use std::io::{self, Read};

fn 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)
}
}

2. Unrecoverable Errors (panic!)

For situations where the program reaches a state that it cannot recover from (like accessing an array out of bounds), Rust provides the panic! macro. When a panic occurs, the program will print a failure message, unwind and clean up the stack, and then quit.

fn main() {
    panic!("crash and burn");
}