RsRust · Lesson 5 of 8

Error Handling

Rust doesn't have exceptions. Instead it has Result<T, E> and Option<T>, which force you to handle errors. This sounds annoying until you use a language that doesn't do this.

Rust
use std::num::ParseIntError;

// Result<T, E> — either Ok(value) or Err(error)
fn parse_number(s: &str) -> Result<i32, ParseIntError> {
    s.trim().parse::<i32>()
}

fn main() {
    // Pattern matching on Result
    match parse_number("42") {
        Ok(n) => println!("Parsed: {}", n),
        Err(e) => println!("Error: {}", e),
    }

    // ? operator — propagate errors upward
    // (only works in functions that return Result or Option)
    let result: Result<i32, _> = (|| {
        let a = parse_number("10")?;
        let b = parse_number("20")?;
        Ok(a + b)
    })();
    println!("{:?}", result);   // Ok(30)

    // unwrap() — panics on Err (fine for scripts, not for libraries)
    let n = parse_number("42").unwrap();  // 42

    // unwrap_or — provide a default
    let n = parse_number("oops").unwrap_or(0);  // 0

    // unwrap_or_else — compute default lazily
    let n = parse_number("oops").unwrap_or_else(|e| {
        eprintln!("Falling back: {}", e);
        -1
    });
}
Rust
// Option<T> — either Some(value) or None
fn first_even(numbers: &[i32]) -> Option<i32> {
    numbers.iter().find(|&&x| x % 2 == 0).copied()
}

fn main() {
    let odds = vec![1, 3, 5, 7];
    let mixed = vec![1, 2, 3, 4];

    println!("{:?}", first_even(&odds));   // None
    println!("{:?}", first_even(&mixed));  // Some(2)

    // if let — concise match for one variant
    if let Some(n) = first_even(&mixed) {
        println!("Found even: {}", n);
    }

    // Option methods
    let opt: Option<i32> = Some(5);
    println!("{}", opt.unwrap_or(0));             // 5
    println!("{:?}", opt.map(|x| x * 2));         // Some(10)
    println!("{:?}", opt.filter(|&x| x > 3));     // Some(5)

    let none: Option<i32> = None;
    println!("{}", none.unwrap_or(42));            // 42
    println!("{:?}", none.map(|x| x * 2));        // None
}
◆ Note
The ? operator is your best friend. It unwraps Ok/Some values and returns early with Err/None if the value is absent. It replaces dozens of match statements and makes error-handling code clean.