code:
struct Foo;
impl Into<u32> for Foo {
fn into(self) -> u32 {
1
}
}
fn main() {
let foo = Foo;
let bar: u32 = foo.into() * 1u32;
}
I get error message.
error[E0283]: type annotations needed
--> src/main.rs:11:24
|
11 | let bar: u32 = foo.into() * 1u32;
| ^^^^
|
note: multiple `impl`s satisfying `Foo: Into<_>` found
--> src/main.rs:3:1
|
3 | impl Into<u32> for Foo {
| ^^^^^^^^^^^^^^^^^^^^^^
= note: and another `impl` found in the `core` crate:
- impl<T, U> Into<U> for T
where U: From<T>;
help: try using a fully qualified path to specify the expected types
|
11 | let bar: u32 = <Foo as Into<T>>::into(foo) * 1u32;
| +++++++++++++++++++++++ ~
For more information about this error, try `rustc --explain E0283`.
error: could not compile `hello` (bin "hello") due to 1 previous error
I can not understand the error message.
What does the error mean? Does it mean the language core also implemented the Into
trait for my struct Foo
and the compiler can not known which one to use? Why does the core crate implement a Into
for me? Where can I learn more about this topic?
core
crate?Does it mean the language core also implemented the
Into
trait for my struct?
No. Language (compiler really) only implements "auto traits" (like Send
, Sync
, etc.). However the standard library contains a bunch of generic trait implementations.
Compiler error speaks about the core
crate. Rust's standard library is split into 3 crates. core
(dependency free, lowest level building blocks), alloc
(everything that involves allocation) and std
(interacting with the OS, reexports items from core
and alloc
crates). So really compiler tells you that there exist some implementation in the standard library (core
part of it).
Traits From
and Into
are reflexive. This means that there exist in the standard library following blanket implementations:
impl<T> From<T> for T { ... }
impl<T, U> Into<U> for T
where
U: From<T>
{ ... }
This both blanket implementations imply impl<T> Into<T> for T
.
This means that using those traits with type inference is tricky. In general you cannot write
let x: _ = Into::into(<expression>);
because compiler cannot infer both types of left hand side pattern and right hand side expression. You might think that you described its type by writing type annotation on bar
:
let bar: u32 = foo.into() * 1u32;
But since you are using *
operator compiler is really invoking some specific implementation of std::ops::Mul
trait. So above line is translated into something like this:
let bar: u32 = <<Some unknown type> as Mul<Rhs=u32>>::mul(foo.into(), 1);
compiler tries to infer <Some unknown type>
, but the only thing it can infer about it, is that this is a type of expression foo.into()
. So we are back to let x: _ = foo.into()
problem.
Notice that if we change order of arguments that we multiply to let bar: u32 = 1u32 * foo.into();
, then compiler will produce an additional error, which further hints at the problem:
error[E0284]: type annotations needed
--> src/main.rs:12:31
|
12 | let bar: u32 = 1u32 * foo.into();
| - ^^^^
| |
| type must be known at this point
|
= note: cannot satisfy `<u32 as Mul<_>>::Output == u32`
help: try using a fully qualified path to specify the expected types
|
12 | let bar: u32 = 1u32 * <Foo as Into<T>>::into(foo);
|
You must do what the compiler ask of you. Specify types, that it cannot infer. For example using fully qualified syntax:
let bar: u32 = <Foo as Into<u32>>::into(foo) * 1u32;
or by defining an intermediate variable:
let bar: u32 = {
let foo: u32 = foo.into();
foo * 1
};