I asked a relevant question about why there is no implementation of From<&String>
for String
. I now want to create my own trait as the following:
#[derive(Debug)]
struct MyStruct(String);
impl MyStruct {
fn new<T>(t: T) -> MyStruct
where
T: MyIntoString,
{
MyStruct(t.my_into())
}
}
trait MyIntoString {
fn my_into(self) -> String;
}
impl<'a> MyIntoString for &'a String {
fn my_into(self) -> String {
self.clone()
}
}
impl<I> MyIntoString for I
where
I: Into<String>,
{
fn my_into(self) -> String {
self.into()
}
}
fn main() {
let s: String = "Hello world!".into();
let st: MyStruct = MyStruct::new(&s);
println!("{:?}", st);
}
The compiler now claims that the two implementations of MyIntoString
are conflicting. This is even weirder to me as we already see in the other question that From<&String>
didn't implement for String
and so it didn't find an implementation of Into<String>
for &String
. So how come this is conflicting now?
Furthermore, even when I turned on #![feature(specialization)]
, the same conflict was detected.
The error message
According to one answer of this question, it looks like the error message didn't guide me to the right track.
So let me post the error message to blame, as it may changed in the future.
error[E0119]: conflicting implementations of trait `MyIntoString` for type `&std::string::String`:
--> src/main.rs:23:1
|
17 | / impl<'a> MyIntoString for &'a String {
18 | | fn my_into(self) -> String {
19 | | self.clone()
20 | | }
21 | | }
| |_- first implementation here
22 |
23 | / impl<I> MyIntoString for I
24 | | where
25 | | I: Into<String>,
26 | | {
... |
29 | | }
30 | | }
| |_^ conflicting implementation for `&std::string::String`
To me, this is a claim by the compiler that there is a REAL conflict, not a potential one.
The error is caused by the orphan rules (see The Book second ed. chapter 10.2 at the end of Implementing a trait on a type).
These prevents your code from breaking when there are minor changes (as per RFC#1105) in crates you use. If the authors of the standard library decided to implement Into<String>
for &String
, then your program would contain a conflicting definition for my_into
and would break. The addition of a trait implementation should be a minor change and shouldn't break your program.
This post provides justification for the rule.
The Book suggests using the newtype pattern to work around this issue.
#[derive(Debug)]
struct MyStruct(String);
impl MyStruct {
fn new<T>(t: T) -> MyStruct
where
T: Into<String>,
{
MyStruct(t.into())
}
}
struct Wrapper<'a>(&'a String);
impl<'a> From<Wrapper<'a>> for String {
fn from(t: Wrapper<'a>) -> String {
t.0.clone()
}
}
fn main() {
let s: String = "Hello world!".into();
let st: MyStruct = MyStruct::new(Wrapper(&s));
println!("{:?}", st);
}
Playground link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With