Back to Blog

Rust Option, Result & ? Operator Explained

Sandy LaneSandy Lane

Video: Rust Option, Result & ? Operator Explained by Taught by Celeste AI - AI Coding Coach

Watch full page →

Rust Option, Result & ? Operator Explained

Rust provides powerful tools to handle errors without exceptions by using the Option and Result types. Option represents values that might be absent, while Result handles operations that can succeed or fail. The ? operator simplifies error propagation, making code cleaner and more readable.

Code

fn main() {
  let numbers = vec![10, 20, 30];

  // Using Option with get()
  match numbers.get(1) {
    Some(&value) => println!("Found: {}", value),
    None => println!("No value found at index 1"),
  }

  match numbers.get(10) {
    Some(&value) => println!("Found: {}", value),
    None => println!("No value found at index 10"),
  }

  // Using unwrap_or to provide a default value
  let value = numbers.get(10).unwrap_or(&0);
  println!("Value at index 10 or default: {}", value);

  // Using Result with parse()
  fn parse_number(s: &str) -> Result {
    s.parse::()
  }

  match parse_number("42") {
    Ok(n) => println!("Parsed number: {}", n),
    Err(e) => println!("Failed to parse: {}", e),
  }

  match parse_number("abc") {
    Ok(n) => println!("Parsed number: {}", n),
    Err(e) => println!("Failed to parse: {}", e),
  }

  // Using unwrap_or with Result to provide a default on error
  let n = parse_number("abc").unwrap_or(-1);
  println!("Parsed or default: {}", n);

  // The ? operator for error propagation
  fn double_parse(s: &str) -> Result {
    let n = s.parse::()?;    // returns Err early if parse fails
    Ok(n * 2)
  }

  match double_parse("21") {
    Ok(n) => println!("Double parsed: {}", n),
    Err(e) => println!("Error doubling parse: {}", e),
  }

  match double_parse("xyz") {
    Ok(n) => println!("Double parsed: {}", n),
    Err(e) => println!("Error doubling parse: {}", e),
  }

  // Chaining multiple ? operators
  fn add_two_numbers(a: &str, b: &str) -> Result {
    let x = a.parse::()?;
    let y = b.parse::()?;
    Ok(x + y)
  }

  match add_two_numbers("10", "20") {
    Ok(sum) => println!("Sum: {}", sum),
    Err(e) => println!("Failed to add: {}", e),
  }
}

Key Points

  • Option represents a value that might be present (Some) or absent (None), avoiding null pointer errors.
  • Result encapsulates success (Ok) and failure (Err) outcomes for fallible operations like parsing.
  • Pattern matching with match enables explicit handling of both success and error cases.
  • unwrap_or provides a default value when Option is None or Result is Err, preventing panics.
  • The ? operator propagates errors automatically, simplifying error handling and reducing boilerplate.