通用特征对象的向量

时间:2019-08-01 20:24:15

标签: generics types enums rust polymorphism

(这是我第二次尝试查找我的确切问题。请参阅编辑历史记录)

我有一个简单的通用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输入什么?我希望它是通用的,所以我不能简单地放在Impl1Impl2那里。我可以做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

1 个答案:

答案 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 Impl2MyTrait<Impl1>是不同的特征,因此MyTrait<Impl2>Impl1没有共同的特征可用于将它们装箱并将它们放入共同的向量中。 / p>

您需要一个具体,它是动态多态性的非通用特征。