Guide

The ? operator

Writing a match for every Result gets long. The ? operator does the common case in one character.

?

Put ? after a Result:

  • If it is Ok(v), you get v and the code keeps going.
  • If it is Err(e), the function returns Err(e) right away.
use std::num::ParseIntError;fn double(s: &str) -> Result<i32, ParseIntError> {    let n = s.parse::<i32>()?;    Ok(n * 2)}

ParseIntError is the error type that parse gives for numbers. It lives at std::num::ParseIntError, so the use line brings it in.

double("21") gives Ok(42). double("x") returns the parse error, and the Ok(n * 2) line never runs. To call a function and ignore the Result it gives back, write let _ = double("x");.

? on Option

? works on Option too, inside a function that returns Option. On None, the function returns None early.

fn second(v: &[i32]) -> Option<i32> {    let x = v.get(1)?;    Some(*x * 10)}

Where ? works

? may return early, so the function's return type must be able to hold what it returns.

  • ? on a Result needs a function that returns a Result with a fitting error type.
  • ? on an Option needs a function that returns an Option.
  • In a function that returns () or i32, ? is error E0277.

main can return Result

A plain fn main() returns (), so ? is not allowed there. Give main a Result return type and end it with Ok(()):

use std::num::ParseIntError;fn main() -> Result<(), ParseIntError> {    let n: i32 = "4".parse()?;    println!("{n}");    Ok(())}

If main returns an Err, Rust prints the error and the program exits with a failure code.

Remember

  • ? unwraps Ok or returns the Err early.
  • On Option, ? unwraps Some or returns None.
  • ? only works when the function returns a matching type (E0277).
  • fn main() -> Result<(), E> lets you use ? in main.