为引用类型和非引用类型实现一个特性会导致冲突的实现。

4
我正在尝试创建一个trait,在其中为所有非引用类型提供一个实现,为所有引用类型提供另一个实现。
这个代码无法编译:
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<T> Foo for T {} 不够?我的意思是,为什么你需要特别为 &mut 引用实现它?你是否还需要另一种类型的实现来处理 &'a T 呢? - trent
&mut T 不是 Clone&mut T 满足 for T(因为 &mut T 是一种类型,所以 impl<T> Bar for T 也实现了每个 &mut T 的 Bar)。克隆版本不会冲突,因为 &mut T 永远不会是 Clone(你不能有两个可变引用)。 - daboross
2个回答

10
正如您所学的,通用类型 T 可以是任何东西¹,因此当第一个 impl 中的 T 是&'a mut U 时,Foo 的实现会重叠(冲突),因为第二个 impl 也涵盖了这种情况(当 T 是 U 时)。
Clone 版本之所以能工作,仅仅是因为 &mut 引用永远不实现 Clone,所以 T where T: Clone 和 &'a mut T 之间不存在重叠²。如果您尝试为不可变(&)引用实现 Bar,则会再次出现冲突,因为不可变引用确实实现了 Clone。
【引用】“我如何在没有它的情况下使其工作?”
如果您的意思是为引用类型实现一种实现,而为非引用类型实现另一种不同的实现,则在 Rust 中不可能做到这一点,原因与无法为 struct 和 enum 实现特定 trait 的不同方式相同:目前 Rust 中根本无法表达它。
您可能的一个常见模式是个体化地为您需要的任何非引用类型实现 trait,然后添加一个“全局 impl”,该 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 { ... }

¹ 好的,至少是任何 Sized 的内容。如果不是这样,您必须添加 ?Sized

² 因为 &'a mut T 永远不会是 Clone,无论 T 自身是否具有 Clone + 'static 属性,所以 where T: Clone + 'static 从句并不重要。


2
< p > "Clone" 版本之所以有效,是因为实现该特质的类型在实现上不再冲突。< /p> < p > 参考第一个示例并添加默认实现。< /p>
trait Foo {
    fn hi(&self){
        println!("Hi");
    }
}

然后,我们使用 impl<T> 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<'a,T> Foo for &'a mut T {} ,因为 impl<T> Foo for T {} 已经足够给你想要的东西了。
现在我们已经看到第一个示例可以在没有第二个实现的情况下正常工作,所以使用 Clone 的示例也就有了意义,因为你正在实现一组类型 T 的子集,这些类型是 Clone 的,另一组类型 &'a mut TClone+static 的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接