我正在尝试创建一个特征并为所有非引用类型提供一个实现,并为所有引用类型提供另一个实现.
这无法编译:
trait Foo {}
impl<T> Foo for T {}
impl<'a, T> Foo for &'a mut T {}
Run Code Online (Sandbox Code Playgroud)
这失败了,错误
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 _`
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这有效:
trait Bar {}
impl<T> Bar for T
where
T: Clone,
{}
impl<'a, T> Bar for &'a mut T
where
T: Clone + 'static,
{}
Run Code Online (Sandbox Code Playgroud)
为什么带Clone约束的版本有效,如何在没有约束的情况下使其工作?
正如你所了解到,通用T可以anything¹,所以Fooimpls重叠(冲突),只要T在第一IMPL是&'a mut U,因为第二IMPL也包括这种情况下,(如果T是U).
该Clone版本只是因为&mut引用永远不会实现Clone,所以T where T: Clone和之间没有重叠&'a mut T.²如果你尝试实现Barimmutable(&)引用,你将再次发生冲突,因为不可变引用确实实现了Clone.
如果没有它,我可以让它工作吗?
如果用"it"表示引用类型的一个实现和非引用类型的另一个实现,那么在Rust中不可能出于同样的原因,你不能用structs的单向方式实现特性,而用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 { ... }
Run Code Online (Sandbox Code Playgroud)
¹好吧,Sized至少是任何事情.你必须添加,?Sized如果这不是你想要的.
²该where T: Clone + 'static条款并不重要,因为&'a mut T永远不会Clone是否T自己.
小智 2
该版本有效的原因Clone是因为正在实现该特征的类型在实现上不再发生冲突。
采取第一个示例并添加默认实现。
trait Foo {
fn hi(&self){
println!("Hi");
}
}
Run Code Online (Sandbox Code Playgroud)
然后我们实现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
}
Run Code Online (Sandbox Code Playgroud)
要回答问题的第二部分,您不需要第二个工具,impl<'a,T> Foo for &'a mut T {}因为impl<T> Foo for T {}它足以满足您的需求。
现在我们已经看到第一个示例在没有第二个实现的情况下也可以工作,因此使用示例开始有意义,Clone因为您正在为以下类型的子集T和Clone不同类型的子集&'a mut T实现Clone+static