Why doesn't String implement From<&String>?

Viewed 293

Background

I know that in Rust people prefer &str rather than &String. But in some case we were only given &String.

One example is when you call std::iter::Iterator::peekable. The return value is a Peekable<I> object that wraps the original iterator into it and gives you one extra method peek.

The point here is that peek only gives you a reference to the iterator item. So if you have an iterator that contains Strings, you only have &String in this case. Of cause, you can easily use as_str to get a &str but in the code I will show below it is equivalent to a call to clone.

The question

This code

#[derive(Debug)]
struct MyStruct(String);

impl MyStruct {
    fn new<T>(t: T) -> MyStruct
    where
        T: Into<String>,
    {
        MyStruct(t.into())
    }
}

fn main() {
    let s: String = "Hello world!".into();
    let st: MyStruct = MyStruct::new(&s);
    println!("{:?}", st);
}

doesn't compile because String doesn't implement From<&String>. This is not intuitive.

Why does this not work? Is it just a missing feature of the standard library or there are some other reasons that prevent the standard library from implementing it?

In the real code, I only have a reference to a String and I know to make it work I only need to call clone instead, but I want to know why.

2 Answers

Since String does implement From<&str>, you can make a simple change:

fn main() {
    let s: String = "Hello world!".into();
    // Replace &s with s.as_str()
    let st: MyStruct = MyStruct::new(s.as_str());
    println!("{:?}", st);
}

All &Strings can be trivially converted into &str via as_str, which is why all APIs should prefer to use &str; it's a strict superset of accepting &String.

Related