Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust: Understanding trait `From` implementation

How to understand trait FromWhatever in rust

The Rust book explains following:

The From trait allows for a type to define how to create itself from another type, hence providing a very simple mechanism for converting between several types.

Sounds simple enough. Lets try as simple example as possible:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

use std::str::FromStr;

struct MyStructure {}

// auto accepted suggestion from language server.
impl FromStr for MyStructure {
    type Err = (); // I've added this

    fn from_str(_s: &str) -> Result<Self, Self::Err> {
        Ok(Self {}) // I've added this
    }
}

fn main() {
    const INPUT: &str = "test";
    let _tmp: MyStructure = MyStructure::from(INPUT);
}

playground

Compiling test_range_2 v0.1.0 (/home/pavel/Repositories/test_range_2)
error[E0308]: mismatched types
   --> src/main.rs:15:47
    |
15  |     let _tmp: MyStructure = MyStructure::from(INPUT);
    |                             ----------------- ^^^^^ expected struct `MyStructure`, found `&str`
    |                             |
    |                             arguments to this function are incorrect
    |
note: associated function defined here
   --> /home/pavel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:374:8
    |
374 |     fn from(_: T) -> Self;
    |        ^^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `test_range_2` due to previous error

So I expected this behavior:

let target: TARGET_TYPE = TARGET_TYPE::from::<SOURCE_TYPE>(input_var: SOURCE_TYPE);

Compared to the example in the rust book:

let num = Number::from(30);

It seems to me like a reasonable assumption.

However, reading the error message: "expected struct MyStructure, found &str". Does that mean that syntax is like this?

let target: TARGET_TYPE = TARGET_TYPE::from::<TARGET_TYPE>(input_var: TARGET_TYPE);

If, that’s true, then code in the rust book should also fail with the error "expected Number, found i32", but it doesn’t.

I expected my solution to work because I’ve implemented the trait FromStr, and I’m trying to create object from &str (see the "from" and "str"?). Which is also the type that was autocompleted by language server after I’ve typed impl FromStr for MyStructure. What am I missing? I want to impl FromStr for all my types but that compiler is not making it easy.

Solution

use std::str::FromStr;

struct MyStructure {}

impl FromStr for MyStructure {
    type Err = ();

    fn from_str(_s: &str) -> Result<Self, Self::Err> {
        Ok(Self {})
    }
}
impl From<&str> for MyStructure {
    fn from(_: &str) -> Self {
        Self {}
    }
}

fn main() {
    const INPUT: &str = "test";
    let _tmp0 = MyStructure::from_str(INPUT);
    let _tmp1 = MyStructure::from(INPUT);
}

I implemented trait FromStr but was referring to trait From<&str>. Since there is a trait in standard lib that looks like this:

trait From<T> -> T

compiler tried to use that in stead.

>Solution :

From and FromStr are completely different and entirely unrelated traits.

The first one performs 1 -> 1 infaillible conversions, while the latter is used to parse strings (it’s a pretty old trait, its modern equivalent is TryFrom but because FromStr hooks into str::parse() it remains convenient and popular).

Here you impl FromStr, which does nothing for your From::from call.

Instead you get told about a blanket implementation: converting a type to itself is a no-op, so the standard library has

impl<T> From<T> for T

which just returns itself.

Hence the compiler’s error message: when it encounters

MyStructure::from(INPUT);

and tries to resolve this to an implementation, the only impl From<?> for MyStructure it finds is the blanket implementation,

impl From<MyStructure> for MyStructure

and thus it tells you that it expects an argument of type MyStructure (the only possible input for the implementations it found), but found an &str (what you actually gave it).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading