Guide

Result

Some work can fail: reading a file, parsing text, dividing by zero. Rust does not hide this. A function that can fail returns a Result.

Result

Result<T, E> is an enum with two variants:

  • Ok(value) - it worked, and here is a T.
  • Err(error) - it failed, and here is an E that says why.
fn half(n: i32) -> Result<i32, String> {    if n % 2 == 0 {        Ok(n / 2)    } else {        Err(String::from("odd"))    }}

Matching a Result

Use match to handle both outcomes. You must cover both Ok and Err, or the code does not compile (E0004).

match half(7) {    Ok(h) => println!("half is {h}"),    Err(e) => println!("error: {e}"),}

Parsing strings

"42".parse::<i32>() turns text into a number. The text might not be a number, so it returns Result<i32, ParseIntError>, not a plain i32. Parsing is strict: " 12" with a space fails.

let good = "42".parse::<i32>();  // Ok(42)let bad = "4x".parse::<i32>();   // Err(...)

Result methods

You do not always need a full match:

  • r.unwrap_or(0) - the value, or 0 if it is an Err.
  • r.ok() - turns Ok(v) into Some(v) and Err into None.
  • r.is_ok() - true if it is an Ok.
  • r.map_err(f) - runs the function f on the error and keeps the Ok as it is.

It is like map on Option, but for the error.

fn label(code: i32) -> String {    format!("error {code}")}let n = "x".parse::<i32>().unwrap_or(0); // 0let r: Result<i32, i32> = Err(404);let m = r.map_err(label); // Err("error 404")

Remember

  • A function that can fail returns Result<T, E>.
  • Ok holds the value, Err holds the error.
  • match must handle both Ok and Err.
  • parse returns a Result, so you must deal with the error.