Recoverable Errors with Result

In this chapter, we'll explore handle errors that can be recovered from gracefully.

Recoverable Errors with Result

Most errors aren't serious enough to stop the program entirely. The Result enum handles recoverable errors:

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Handling Results

module main
 
use std::fs::File
 
fn main() -> void {
    let file = File::open("hello.txt")
 
    let file = match file {
        Ok(f) => f,
        Err(error) => panic("Problem opening file: ", error),
    }
}

Different Error Types

Handle different errors differently:

module main
 
use std::fs::File
use std::io::ErrorKind
 
fn main() -> void {
    let file = match File::open("hello.txt") {
        Ok(f) => f,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic("Problem creating file: ", e),
            },
            other_error => panic("Problem opening file: ", other_error),
        }
    }
}

Shortcuts: unwrap and expect

For quick prototyping:

// Panics with generic message if Err
let file = File::open("hello.txt").unwrap()
 
// Panics with custom message if Err
let file = File::open("hello.txt")
    .expect("hello.txt should exist")

Propagating Errors

Return errors to the caller:

fn read_username_from_file() -> Result<string, io::Error> {
    let file = File::open("hello.txt")
 
    let mut file = match file {
        Ok(f) => f,
        Err(e) => return Err(e),
    }
 
    let mut username = String::new()
 
    return match file.read_to_string(username) {
        Ok(_) => Ok(username),
        Err(e) => Err(e),
    }
}

The ? Operator

The ? operator is shorthand for error propagation:

fn read_username_from_file() -> Result<string, io::Error> {
    let mut file = File::open("hello.txt")?
    let mut username = String::new()
    file.read_to_string(username)?
    return Ok(username)
}

Even more concise with chaining:

fn read_username_from_file() -> Result<string, io::Error> {
    let mut username = String::new()
    File::open("hello.txt")?.read_to_string(username)?
    return Ok(username)
}

The ? operator:

  • Returns the value inside Ok if successful
  • Returns early with the Err if there's an error

Continue to To panic! or Not to panic!.