Rust Condition Handling

  • No exceptions (except panics which cannot [normally] be caught)

  • Normally indicate using Option and Result. std says something vaguely like

    enum Option<T> {
        Some(T),
        None,
    }
    
    enum Result<T, E> {
        Ok(T),
        Err(E),
    }
    
  • Definitely read the API docs for std::option::Option and std::result::Result carefully

Unwrap and Expect

  • Methods of Option and Result . .unwrap() panics with a generic message on failure, .expect("x") panics with the message "x" on failure

  • Panic on None or Err, otherwise return the contents of Some or Ok

    let n = Some(7).unwrap(); // n is now 7
    let n = None.unwrap(); // program panics
    

Pattern Matching

  • Easiest to understand, but most verbose: just deal with the enum directly

    // Print a str backward.
    let mut s = "hello".to_string();
    while let Some(c) = s.pop() {
        print!("{}", c);
    }
    println!();
    
    // Read from stdin with default.
    let stdin = std::io::stdin();
    let mut line = String::new();
    match stdin.lock().read_line(&mut line) {
        Ok(_) => (),
        Err(e) => line = "".to_string(),
    }
    

Try (?)

  • Rust 2018 has the ? operator. This takes an Option or Result and unwraps if good, early-returns from the calling function with the error otherwise

    fn read_num() -> Result<u64, Box<dyn std::error::Error>> {
        use std::io::BufRead;
        let stdin = std::io::stdin();
        let mut line = String::new();
        let _ = stdin.lock().read_line(&mut line)?;
        Ok(line.trim().parse()?)
    }
    
  • More recently, it has become allowed to declare main() to return a Result:

    fn main() -> Result<(), Box<dyn std::error::Error>>
    

    If main() returns an Err you will get an error message formatted some debuggy way

Error Combinators

  • It is common to handle errors in a "functional" style using methods provided by Result and Option. This is handy when you want to keep going after an error

    (0..n).sum().and_then(|s| s / n).or_else(0)
    
  • This usage can be worth it, but can also be a bit tricky. It will take some practice

Last modified: Wednesday, 15 January 2020, 4:17 PM