rustsyntax

What is this question mark operator about?


I'm reading the documentation for File:

//..
let mut file = File::create("foo.txt")?;
//..

What is the ? in this line? I do not recall seeing it in the Rust Book before.


Solution

  • As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).

    In Rust, error handling uses Result. A typical example would be:

    fn halves_if_even(i: i32) -> Result<i32, Error> {
        if i % 2 == 0 {
            Ok(i / 2)
        } else {
            Err(/* something */)
        }
    }
    
    fn do_the_thing(i: i32) -> Result<i32, Error> {
        let i = match halves_if_even(i) {
            Ok(i) => i,
            Err(e) => return Err(e),
        };
    
        // use `i`
    }
    

    This is great because:

    It's less than ideal, however, in that it is very verbose. This is where the question mark operator ? comes in.

    The above can be rewritten as:

    fn do_the_thing(i: i32) -> Result<i32, Error> {
        let i = halves_if_even(i)?;
    
        // use `i`
    }
    

    which is much more concise.

    What ? does here is equivalent to the match statement above with an addition. In short:

    1. It unpacks the Result if OK
    2. It returns the error if not, calling From::from on the error value to potentially convert it to another type.

    It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?.

    One example of the magic is that this also works for Option:

    // Assume
    // fn halves_if_even(i: i32) -> Option<i32>
    
    fn do_the_thing(i: i32) -> Option<i32> {
        let i = halves_if_even(i)?;
    
        // use `i`
    }
    

    The ? operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try trait.

    See also: