So, there's a bit of history here. In old versions of Rust, it wasn't possible to write impl From<MyType> for StdType
, because that's an implementation of an upstream trait for an upstream type, and you had to use impl Into<StdType> for MyType
instead. Nowadays, From<MyType>
is considered as a local trait for impl coherence if MyType
is local, so that impl is valid.
If it were never necessary to write impl Into
from the beginning, the trait might have been designed differently; namely, as
trait Into: Sized {
fn into<T: From<Self>>(self) -> T { T::from(self) }
}
impl<T> Into for T {}
Note how this is different from the trait as it's actually defined:
trait Into<T>: Sized {
fn into(self) -> T;
}
impl<T, U: From<T>> Into<U> for T {
fn into(self) -> U { U::from(self) }
}
var.into::<U>()
applies the turbofish type to the function, so it would ascribe the output type with the function generic spelling, but is a compile error for the trait generic spelling, since the function isn't generic. Making var.into::<U>()
work as-is to specify the trait generic would indeed break uses of generic methods on generic traits, since which generic is being specified would then be ambiguous.
Technically this could theoretically be "fixed" by making a new trait Into
and putting that one into the editionNext prelude instead of the current one — it's already the case that ?
on Result
only works with From
impls, not Into
— but this is an extremely inelegant hack to fix a fairly minor papercut. That definition is basically what tap::Conv
uses, it just suffers from not being default available like Into
.
IMHO, the best "solution" is something that's also desirable for other reasons — universal method call syntax (UMCS), i.e. permitting you to write something like var.(U::from)()
instead of needing the Into
trait to forward method syntax to From::from
. It is unfortunate that the first exposure to turbofish syntax is usually collect
's generic return type, and into
doesn't work the same way, but this does offer a chance to explain what a turbofish is actually specifying, and how Into::into
differs from Iterator::collect
.