Can't pass str in for Into<String>

I was surpised to discover that the usual trick to take impl Into<T> to make it so callers don't have to call into themselves doesn't seem to work for strings. It keeps complaining that str is unsized, even after I try to tell it unsized types are okay with ?Sized. What am I missing here?

#![allow(dead_code)]
#![allow(unused_variables)]

fn test(a: &(impl Into<String> + ?Sized)) // presence of ?Sized makes no difference, strangely
{
}

fn test2(a: String)
{
}

fn main()
{
    //test("Hello world"); // fails to compile
    test2("Hello world".into()); // but this is allowed, suggesting str impls Into<String>
}

Playground link

str always needs a level of indirection. If you want your first example to compile, then try with this:

fn test(a: impl Into<String>) -> String {
  a.into()
}

playground

2 Likes

You can't move unsized types (pass or return them to functions). (We might get some ability for local unsized values eventually.)

str: Into<String> isn't satisfied. &str: Into<String> is satisfied.

The length of a str is stored in a wide pointer (&str consists of a pointer to the string data and a usize for the length in UTF8 bytes).

2 Likes

Oh I misunderstood the complaint, I thought it had to do with generic args being Sized by default. It just doesn't want you passing unsized things by value.

I did as you suggested, which works, but I thought it would prevent passing in &String since the argument is now by-value. But it actually works, why?

#![allow(dead_code)]
#![allow(unused_variables)]

fn test(a: (impl Into<String> + ?Sized)) // presence of ?Sized makes no difference, strangely
{
}

fn main()
{
    test("Hello world"); // makes sense
    test("Hello world".to_string()); // makes sense
    let c = "Hello world".to_string();
    test(&c); // why does this work? argument is by-value not ref.
}

I thought maybe there would be something making it so if U: From<T> then U: From<&T> but I don't see such an impl.

There's a From<&String> for String.

2 Likes

T and &T are different types, as much as T and Box<T>. Traits implemented for &T aren't auto implemented for T, for example. This is why we have the implementation that @quinedot posted above.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.