为引用类型和非引用类型实现特征会导致实现冲突

  • 本文关键字:引用类型 实现 冲突 特征 rust
  • 更新时间 :
  • 英文 :


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

这无法编译:

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约束的版本可以工作,如何在没有它的情况下使其工作?

如您所知,泛型T可以是任何东西¹,因此每当第一个 impl 中的T&'a mut U时,Fooimpls 就会重叠(冲突),因为第二个 impl 也涵盖了这种情况(当TU时)。

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

[H]没有它我能让它工作吗?

如果您所说的"它"是指引用类型的一种实现,而非引用类型的另一种实现,那么在 Rust 中这是不可能的,原因相同,您不能以一种方式实现structs 和另一种方式实现enums 的特征:根本没有办法表达它(在当前的 Rust 中)。

一种可能适合您的常见模式是为您需要的任何非引用类型单独实现您的特征,然后添加一个"blanket impl",涵盖对已经实现该特征的类型的任何引用,例如:

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

²where T: Clone + 'static子句无关紧要,因为无论T本身是否&'a mut T都不会Clone

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

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

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

然后,我们为所有类型T实现Fooimpl<T> Foo for T {}这实际上实现了足够的功能,让我们可以使用对类型的引用并使用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的示例开始有意义,因为您正在实现Clone类型的子集TClone+static的不同类型子集&'a mut T

相关内容

最新更新