Using Turbofish with the "into" method?

Thanks for all the help so far!

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}");
}

The method into is not generic. The trait Into is generic.

It works the same with types.

Here's what it looks like to move the generic to a method.

3 Likes

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.

Into could be defined as

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

There's tap::Conv blanket-implemented for all (Sized) types, by the way, which works exactly like this.

2 Likes