Lesson 14 / 25

Result and the ? Operator

Errors in the type signature.

Ok, Err and early return

Functions that can fail return Result<T, E>: Ok(value) or Err(error). The ? operator unwraps an Ok value or returns the error from the current function immediately, keeping the happy path readable. Callers then match on the result or propagate it further. Because errors are part of the type, the compiler warns if you ignore a Result.

Recoverable versus unrecoverable

Result and ? propagate recoverable errors; panics stop on bugs.

Three ideas: Result and ?, custom errors, panics.
Figure 5.1 — Result, custom errors and panics.

Parsing with ? and handling the error, run

I ran this with Rust 1.99.0 (cargo run, edition 2024, standard library only). Adding "3" and " 4 " gives Ok(7). "four" fails to parse, and ? returns the ParseIntError immediately. The match prints the error's message for the negative number, which is not a valid u32.

use std::num::ParseIntError;

fn parse_qty(s: &str) -> Result<u32, ParseIntError> {
    s.trim().parse::<u32>()
}

fn total(a: &str, b: &str) -> Result<u32, ParseIntError> {
    let x = parse_qty(a)?;   // ? returns the error early
    let y = parse_qty(b)?;
    Ok(x + y)
}

fn main() {
    println!("{:?}", total("3", " 4 "));
    println!("{:?}", total("3", "four"));
    match total("10", "-1") {
        Ok(n) => println!("ok {n}"),
        Err(e) => println!("could not add: {e}"),
    }
}

Output:

Ok(7)
Err(ParseIntError { kind: InvalidDigit })
could not add: invalid digit found in string

Use ? liberally

Propagate errors with ? and handle them at a boundary (main, a request handler) where you can report or recover.

Quick check: What does the ? operator do on an Err value?

  • Converts it to None silently
  • Panics
  • Ignores the error
  • Returns the error from the current function
Answer

Returns the error from the current function — Early return keeps code flat.