我试图创建一个特征,为所有非引用类型提供一个实现,为所有引用类型提供另一个实现。
无法编译:
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
约束的版本有效,如何在没有它的情况下使其工作?
答案 0 :(得分:6)
根据您的了解,通用T
可以是任何¹,因此Foo
只要第一个impl中的T
为&'a mut U
,就会重叠(冲突),因为第二个impl也涵盖了这种情况(当T
为U
时)。
Clone
版本的工作原理只是因为&mut
引用从未实现Clone
,因此T where T: Clone
和&'a mut T
之间没有重叠.²如果您尝试实施Bar
对于不可变(&
)引用,您将再次发生冲突,因为不可变引用执行实现Clone
。
[H]我可以在没有它的情况下使它工作吗?
如果用“it”表示引用类型的一个实现,而另一个是非引用类型的实现,那么在Rust中不可能出于同样的原因而无法为struct
单向实现特征s和enum
的另一种方式:根本没有办法表达它(在当前的Rust中)。
可能为您工作的一个常见模式是为您需要的任何非引用类型单独实现您的特征,然后添加“覆盖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
的任何事情。 You have to add ?Sized
if that's not what you want.
²where T: Clone + 'static
子句并不重要,因为&'a mut T
永远不会是Clone
T
本身是不是。{/ p>
答案 1 :(得分:2)
Clone
版本工作的原因是因为实现特征的类型不再在实现上发生冲突。
采用第一个示例并添加默认实现。
trait Foo {
fn hi(&self){
println!("Hi");
}
}
然后我们为所有类型Foo
实施T
impl<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
的示例有效,因为您正在为T
的{{1}}类型的子集实现{{ 1}}和Clone
&'a mut T
类型的不同子集