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

时间:2017-07-16 07:26:50

标签: rust traits

我向relevant question询问了为什么From<&String>没有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);
}

编译器现在声称MyIntoString的两个实现是冲突的。这对我来说更加怪异,因为我们已经在From<&String>未对String实施的其他问题中看到,因此它没有找到Into<String>的实现&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`

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

2 个答案:

答案 0 :(得分:3)

错误是由孤儿规则引起的(参见本书第二版,Implementing a trait on a type末尾的第10.2章)。

这会阻止您的代码在您使用的包中进行微小更改(根据RFC#1105)时中断。如果标准库的作者决定为Into<String>实施&String,那么您的程序将包含my_into的冲突定义并将中断。添加特征实施应该是一个小的改变,不应该破坏你的程序。

This post为规则提供了理由。

本书建议使用newtype pattern解决此问题。

#[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

答案 1 :(得分:0)

此代码适用于专业化

#![feature(specialization)]

#[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()
    }
}

default impl<I> MyIntoString for I 
{
    default fn my_into(self) -> String {
        String::from("FOO")
    }
}

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

所以,AFAIU,您的版本无法专业化,因为编译器无法确定哪个版本更多specialized

修改

为什么上一个问题的代码无法编译? 因为当您将&s传递给<{p>}中的new

    let st: MyStruct = MyStruct::new(&s);

编译器将&s视为&String,并从std中的代码中看到:

impl<T, U> Into<U> for T where U: From<T>

impl<T, U> Into<U> for T where U: From<T> {
    fn into(self) -> U {
        U::from(self)
    }
}

// From (and thus Into) is reflexive
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> From<T> for T {
    fn from(t: T) -> T { t }
}

由于From<&String>未实现String,因此显示编译错误。因此,您必须明确说明&s是可以构建String的类型,即&str

    let st: MyStruct = MyStruct::new(&s as &str);

现在编译器可以看到这个

impl<'a> From<&'a str> for String
  

编译器现在宣称MyIntoString的两个实现是&gt;相互矛盾的。这对我来说更加怪异,因为我们已经在另一个中看到了&gt;来自&lt;&amp; String&gt;的问题没有实现String,所以它   没有找到Into for&amp; String

的实现

错误的发生只是因为即使您使用专门化,编译器也无法确定哪个实现更多specialized