【问题标题】:Implementing a trait for reference and non reference types causes conflicting implementations为引用和非引用类型实现特征会导致实现冲突
【发布时间】:2018-01-26 00:56:21
【问题描述】:

我正在尝试创建一个特征并为所有非引用类型提供一种实现,并为所有引用类型提供另一种实现。

编译失败:

trait Foo {}
impl<T> Foo for T {}
impl<'a, T> Foo for &'a mut T {}

这会失败并出现错误

error[E0119]: conflicting implementations of trait `Foo` for type `&mut _`:
 --> src/main.rs:3:1
  |
2 | impl<T> Foo for T {}
  | -------------------- first implementation here
3 | impl<'a, T> Foo for &'a mut T {}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut _`

奇怪的是,这行得通:

trait Bar {}

impl<T> Bar for T
where
    T: Clone,
{}

impl<'a, T> Bar for &'a mut T
where
    T: Clone + 'static,
{}

为什么带有Clone 约束的版本可以工作,没有它我如何使它工作?

【问题讨论】:

  • 为什么impl&lt;T&gt; Foo for T {} 不够用?我的意思是,为什么你需要专门为&amp;mut 引用实现它? &amp;'a T 还需要另一种实现方式吗?
  • &amp;mut T 不是Clone&amp;mut T 确实满足 for T(因为 &mut T 是一种类型,impl&lt;T&gt; Bar for T 也为每个 &amp;mut T 实现 Bar)。克隆版本不会冲突,因为 &amp;mut T 永远不会是 Clone(你不能有两个可变引用)。

标签: rust


【解决方案1】:

正如您所了解的,通用 T 可以是任何东西¹,因此只要第一个 impl 中的 T&amp;'a mut UFoo impls 就会重叠(冲突),因为第二个 impl 也涵盖了这种情况(当TU)。

Clone 版本之所以有效,仅仅是因为&amp;mut 引用永远不会实现Clone,因此T where T: Clone&amp;'a mut T 之间没有重叠。² 如果您尝试为不可变(&amp;)实现Bar引用,您将再次发生冲突,因为不可变引用确实实现了Clone

[H]没有它我怎样才能让它工作?

如果“它”是指引用类型的一种实现和非引用类型的另一种不同的实现,这在 Rust 中是不可能的,原因与您不能以一种方式为 structs 和enums 的另一种方式:根本没有办法表达它(在当前的 Rust 中)。

可能对你有用的一个常见模式是为你需要的任何非引用类型单独实现你的特征,然后添加一个“blanket impl”来涵盖对一个类型的任何引用, trait 已经实现,例如:

impl Foo for u32 { ... }
impl Foo for i32 { ... }
impl<'a, T> Foo for &'a T where T: Foo + 'a { ... }
impl<'a, T> Foo for &'a mut T where T: Foo + 'a { ... }

¹好吧,至少是SizedYou have to add ?Sized if that's not what you want.

² where T: Clone + 'static 子句无关紧要,因为无论T 本身是否存在,&amp;'a mut T 永远不会是 Clone

【讨论】:

    【解决方案2】:

    Clone 版本有效的原因是,实现特征的类型在实现上不再冲突。

    以第一个示例并添加默认实现。

    trait Foo {
        fn hi(&self){
            println!("Hi");
        }
    }
    

    然后我们用impl&lt;T&gt; Foo for T {} 为所有T 类型实现Foo,这实际上实现了足以让我们使用对我们的类型的引用并使用Foo 特征。例如:

    fn say_hi<'a>(b: &'a mut Foo){
        b.hi();
    }
    
    fn main(){
        let mut five = 5;
    
        five.hi(); // integer using Foo
        say_hi(&mut five); // &'a mut Foo
    }
    

    要回答您问题的第二部分,您不需要 impl&lt;'a,T&gt; Foo for &amp;'a mut T {} 的第二个实现,因为 impl&lt;T&gt; Foo for T {} 足以为您提供所需的内容。

    既然我们已经看到第一个示例在没有第二个实现的情况下也可以工作,那么使用 Clone 的示例开始变得有意义了,因为您正在实现 T 类型的子集 Clone 和不同的&amp;'a mut T 类型的子集 Clone+static

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多