HiveBrain v1.2.0
Get Started
← Back to all entries
patternrustCritical

What is this question mark operator about?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
aboutmarkthisoperatorwhatquestion

Problem

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 {
    if i % 2 == 0 {
        Ok(i / 2)
    } else {
        Err(/* something */)
    }
}

fn do_the_thing(i: i32) -> Result {
    let i = match halves_if_even(i) {
        Ok(i) => i,
        Err(e) => return Err(e),
    };

    // use `i`
}


This is great because:

  • when writing the code you cannot accidentally forget to deal with the error,



  • when reading the code you can immediately see that there is a potential for error right here.



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 {
    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:

  • It unpacks the Result if OK



  • 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

fn do_the_thing(i: i32) -> Option {
    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:

  • Is the question mark operator ? equivalent to the try! macro?



  • Why do try!() and ? not compile when used in a function that doesn't return Option or Result?

Code Snippets

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`
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = halves_if_even(i)?;

    // use `i`
}
// 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`
}

Context

Stack Overflow Q#42917566, score: 402

Revisions (0)

No revisions yet.