如果没有为`&String`实现`Into <String>`,为什么这些实现会发生冲突?

Ear*_*ine 5 traits rust

我问了一个相关的问题,为什么没有执行From<&String>for String.我现在想要创建自己的特征,如下所示:

#[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);
}
Run Code Online (Sandbox Code Playgroud)

编译器现在声称两个实现MyIntoString是冲突的.这对我来说更加怪异,因为我们已经在另一个From<&String>没有实现的问题中看到了String,所以它没有找到Into<String>for 的实现&String.那么现在为何如此矛盾呢?

此外,即使我打开#![feature(specialization)],也检测到相同的冲突.

错误消息

根据这个问题的一个答案,看起来错误信息并没有引导我走上正轨.

因此,让我发布错误消息,因为它可能会在未来发生变化.

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`
Run Code Online (Sandbox Code Playgroud)

对我来说,这是编译器声称存在真正的冲突,而不是潜在冲突.

red*_*ime 3

该错误是由孤儿规则引起的(请参阅本书第二版第 10.2 章,位于“在类型上实现特征”末尾)。

当您使用的 crate发生微小更改(根据RFC#1105 )时,这些可以防止您的代码被破坏。如果标准库的作者决定实现Into<String>for &String,那么您的程序将包含冲突的 for 定义my_into,并且会中断。添加特征实现应该是一个小的改变,并且不应该破坏你的程序。

这篇文章为该规则提供了理由。

本书建议使用新类型模式来解决这个问题。

#[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);
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

  • 不会。 `MyIntoString` 的全面实现(即 `impl&lt;I: Into&lt;String&gt;&gt; MyIntoString for I`)与 `impl MyIntoString for &amp;String` 相结合,可能会因标准库中的微小更改而导致代码损坏。新类型变体不会破坏。 (2认同)
  • 我不明白孤儿规则是如何相关的,因为 OP 正在实现他自己的特征“MyIntoString”。 (2认同)