(这是我第二次尝试查找我的确切问题。请参阅编辑历史记录)
我有一个简单的通用Trait和两个不同的实现:
pub trait MyTrait<T=Self> where T: MyTrait {
}
struct Impl1;
impl MyTrait for Impl1 {
}
struct Impl2;
impl MyTrait for Impl2 {
}
我现在想要一个包含两个实现的元素的向量。据我所知here,我会做:
fn foo() {
let mut traits: Vec<Box<MyTrait>> = Vec::new();
traits.push(Box::new(Impl1{}));
traits.push(Box::new(Impl2{}));
}
但是编译器不同意:
error[E0393]: the type parameter `T` must be explicitly specified
--> src/main.rs:25
|
25 | let mut traits: Vec<Box<MyTrait>> = Vec::new();
| ^^^^^^^ missing reference to `T`
|
= note: because of the default `Self` reference, type parameters must be specified on object types
一方面,这是有道理的。另一方面,我应该为T
输入什么?我希望它是通用的,所以我不能简单地放在Impl1
或Impl2
那里。我可以做Vec<Box<MyTrait<MyTrait>>>
,但这只会移动错误,而不能解决。
修改
上面的代码是最小的失败代码,这是最小的实现:
enum MyEnum<T: MyTrait> {
A(T),
B
}
pub trait MyTrait<T=Self> where T: MyTrait {
fn do_stuff(self) -> MyEnum<T>;
}
struct Impl1;
impl MyTrait for Impl1 {
fn do_stuff(self) -> MyEnum<Impl1> {
MyEnum::A(self)
}
}
struct Impl2;
impl MyTrait for Impl2 {
fn do_stuff(self) -> MyEnum<Impl2> {
MyEnum::B
}
}
每个MyTrait
对象都会消耗自己,并且可能导致MyEnum::A
包含另一个MyTrait
对象或MyEnum::B
。
答案 0 :(得分:1)
泛型的事物-无论是特征,类型还是函数-都不是可以寻址的代码,而仅仅是替换它们时要生成的代码的模板。因此它们不是“对象安全”的,即您不能将它们用于动态引用和智能指针的类型。您只能使用他们的特定实例。
get_density
是通用的,因此您不能拥有MyTrait
或&dyn MyTrait
。您只能拥有Box<dyn MyTrait>
或&dyn MyTrait<Impl1>
。
您确实为参数设置了默认值,但是Box<dyn MyTrait<Impl1>>
是特殊的,因为Self
是实现特征的类型,因此仅在Self
定义中有意义。但是不在试图声明impl
的自由函数中。这就是为什么它无法编译的原因。
此外,由于Vec<Box<MyTrait>>
的特殊性,Self
变为impl MyTrait for Impl1
,而impl MyTrait<Impl1> for Impl1
变为impl MyTrait for Impl2
。由于impl MyTrait<Impl2> for Impl2
与MyTrait<Impl1>
是不同的特征,因此MyTrait<Impl2>
和Impl1
没有共同的特征可用于将它们装箱并将它们放入共同的向量中。 / p>
您需要一个具体,它是动态多态性的非通用特征。