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

我有一个简单的通用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对象的MyTraitMyEnum::B

最佳答案

泛型的事物(无论是特征,类型还是函数)都不是可以寻址的代码,而仅仅是替换它们时要生成的代码的模板。因此它们不是“对象安全”的,即您不能将它们用于动态引用和智能指针的类型。您只能使用它们的特定实例。
MyTrait是通用的,因此您不能拥有&dyn MyTraitBox<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>不同的特征,因此没有Impl1Impl2的公共(public)特征可用于将它们装箱并放入公共(public)向量中。

您需要一个具体的,非通用的动态多态性状。

关于generics - 通用特征对象的向量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57316518/

10-10 19:10