When calling into one has to define the expected type. I tried to use the Turbofish syntaxt, but Rust did not like it. Did I do it incorrectly (the commented out code) or is it only available in the long form at the end of the example?
And if this is the case, why?
fn main() {
let a = "Hello World!";
println!("{a}");
let b = String::from(a);
println!("{b}");
let c: String = a.into();
println!("{c}");
// let d = a.into::<String>();
// method takes 0 generic arguments but 1 generic argument was supplied
// println!("{d}");
let e = Into::<String>::into(a);
println!("{e}");
}
Because you are putting the generic param in the wrong place. It's Into<T>::into, not Into::into<T>.
It's completely logical, too. If it were the way you wanted, that would mean that once a type implements the (single, non-generic, hypothetical) Into trait, it could be turned into any other type whatsoever! That clearly shouldn't even occur to you as something that could be possible.
trait Into: Sized {
fn into<T: From<Self>>(self) -> T {
T::from(self)
}
}
impl Into for T where T: Sized {}
and indeed you can write that (and call it To::to or whatever) if you want a turbofishable into. Std’s Into doesn’t look like that, at least due to the need to sometimes impl Into manually, without a corresponding From – I think it’s rare these days but used to be more common before the orphan rules were relaxed.
The problem with that is exactly the From<Self> bound – while the blanket impl is useful and pervasive, the definition above is not equivalent with the current definition, and is strictly more restrictive.
(Not to mention the conceptual difference – IMO even if the bound makes this possible, the non-generic Into trait would be the wrong way to model the relationship.)