nz_21
nz_21

Reputation: 7343

How does the ? operator interact with the From trait?

Say I have the following:

use std::fs::File;

impl From<i32> for Blah {

    fn from(b:i32) -> Blah {
        Blah {}
    }
}

fn main() {}

enum MyError {
    ParseError,
}

impl From<std::io::Error> for MyError {
    fn from(_:std::io::Error) -> Self {
        MyError::ParseError
    }
}

fn get_result() -> Result<Blah, MyError> {
    let mut file = File::create("foo.txt")?;
}

This compiles fine. I don't understand how.

File::create throws an std::io::error, which we're trying to wrap in a MyError. But we never explicitly call from anywhere!? How does it compile?

As the comments from this answer Rust understanding From trait indicate, you do have to explicitly call from.

So, how is the above snippet compiling?

Upvotes: 1

Views: 94

Answers (2)

MB-F
MB-F

Reputation: 23637

The magic is in the ? operator.

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

expands to something like (source)

let mut file = match File::create("foo.txt") {
    Ok(t)  => t,
    Err(e) => return Err(e.into()),
};

This uses the Into trait, which is the counterpart to the From trait: e.into() is equivalent to T::from(e). Here you have the explicit conversion.

(There is an automatic impl<T, U> Into<U> for T for every impl<T, U> From<T> for U, which is why implementing From is enough.)

Upvotes: 4

E_net4
E_net4

Reputation: 29972

The difference is stated in The Rust Programming Language, chapter 9, section 2, when talking about the ? operator:

Error values that have the ? operator called on them go through the from function, defined in the From trait in the standard library, which is used to convert errors from one type into another. When the ? operator calls the from function, the error type received is converted into the error type defined in the return type of the current function. This is useful when a function returns one error type to represent all the ways a function might fail, even if parts might fail for many different reasons. As long as each error type implements the from function to define how to convert itself to the returned error type, the ? operator takes care of the conversion automatically.

You have provided this implementation of From<std::io::Error> for that error type, therefore the code will work and convert values of this type automatically.

Upvotes: 4

Related Questions