Why is the String implementation not executing from <& String>?

Background

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

For example, you call std::iter::Iterator::peekable . The return value is a Peekable<I> object that wraps the original iterator in it and gives you one additional peek method.

The thing is, peek gives you a reference to an iterator element. Therefore, if you have an iterator containing String s, in this case you have &String . Because of this, you can easily use as_str to get &str , but in the code I'll show below, it is equivalent to calling clone .

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

does not compile because String does not implement From<&String> . This is not intuitive.

Why is this not working? Is this just a missing feature of the standard library, or are there some other reasons that impede the implementation of the standard library?

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

+3
source share
1 answer

To solve your problem, you can imagine how to add a new standard library to the standard library:

 impl<'a, T: Clone> From<&'a T> for T { ... } 

Or make it more general:

 impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... } 

However, there are two problems with this:

  • Specialization : The specialization function, which allows trait-impls to overlap, is still unstable. It turns out that designing a specialization in a sound way is more complicated than expected (mainly because of its lifetime).

    Not being stable, Rust developers are very careful not to expose this function somewhere in the standard public API. This does not mean that it is not used at all in std! A famous example is the specialized ToString impl for str . It was introduced in this PR . As you can read in the discussion of PR, they only accepted it because it does not change the API ( to_string() already implemented for str ).

    However, it differs in that we add a common attribute above: it will change the API. Thus, it is not yet allowed in std.

  • core vs std : From and Into traits are defined in the core library , while Clone and ToOwned defined in std . This means that we cannot add a general impl to core , because core does not know anything about std . But we also can’t add a generic impl to std , because shared imms must be in the same box as the property (this is a consequence of orphaned rules).

    Thus, this would require some form of refactoring and moving around definitions (which may or may not be difficult) before such a general impl can be added.


Please note that adding

 impl<'a> From<&'a String> for String { ... } 

... works just fine. It does not require specialization and does not have problems with orphan rules. But, of course, we would not want to add a specific imp when the general impl made sense.

(thanks to the wonderful people from IRC for explaining to me)

+4
source

Source: https://habr.com/ru/post/1269861/


All Articles