0

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:

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.

3
  • 1
    That page refers specifically to core::convert::From. FromStr is a different trait with different methods and expectations. They are not linked in such a way that would allow you to do MyStructure::from(INPUT). Commented Dec 7, 2022 at 15:04
  • 1
    If you want to use From, why are you using FromStr? Commented Dec 7, 2022 at 15:05
  • @DanGetz ahh. Didn't notice that one. Thanks Commented Dec 7, 2022 at 15:19

1 Answer 1

4

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).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.