特征中具有关联类型的多态结构向量

Vector of polymorphic structs with an associated type in trait

我想了解 多态性 在使用具有关联类型 的特征时如何工作 。考虑以下特征:

trait Animal {
    fn talk (&self);
}

此特性被以下结构使用:

struct Dog;
struct Cow;

impl Animal for Dog {
    fn talk (&self) {
        println!("Woof");
    }
}

impl Animal for Cow {
    fn talk (&self) {
        println!("Moo");
    }
}

然后我遍历 Vec<&Animal>,多态性在这里工作得很好:

fn main() {
    let animals: Vec<&Animal> = vec![&Dog, &Cow];
    for animal in &animals {
        animal.talk();
    }
}
// output:
// Woof
// Moo

到目前为止一切顺利。现在,我添加一个关联类型 Food到特征(该类型未使用,但仅用于最小复制)。

struct Meat;
struct Herb;

trait Animal {
    type Food;
    ...
}
impl Animal for Dog {
    type Food = Meat;
    ...
}
impl Animal for Cow {
    type Food = Herb;
    ...
}

现在我得到错误:

error[E0191]: the value of the associated type `Food` (from trait `Animal`) must be specified
   --> src/main.rs:188:23
163 |     type Food;
    |     ---------- `Food` defined here
...
188 |     let animals: Vec<&Animal> = vec![&Dog, &Cow];
    |                       ^^^^^^ help: specify the associated type: `Animal<Food = Type>`

但在这种情况下,我不能只遵循错误消息,因为实现特征 Animalstruct 的数量不应该是静态的。

Rust 解决这个问题的方法是什么?提前致谢

&Animal &dyn Animal. dyn Animal is a trait object type, and it only exists for a given trait if the trait is object-safe。具有关联类型的特征不是对象安全的,因为 dyn Animal 无法在不指定关联类型 Food

的情况下实现 Animal

这是运行时多态性(trait objects)固有的局限性:你不知道具体的类型,所以你无法知道它的关联类型。²

如果你想创建一个可以调用 .talk() 的东西的向量,很容易为此创建一个特征 (playground):

trait Talk {
    fn talk(&self);
}

impl<A: Animal> Talk for A {
    fn talk(&self) {
        Animal::talk(self);
    }
}

let animals: Vec<&dyn Talk> = vec![&Dog, &Cow];

您将无法编写任何通过 &dyn Talk 使用 Food 的代码,这就是重点:Food 取决于具体类型,而您的向量包含多个具体类型。

另见

  • What makes something a "trait object"?

¹ 您 可以 创建所有具有 相同 关联类型的特征对象,例如 dyn Animal<Food = Herb>。这在 Iterator 中很常见,如 Box<dyn Iterator<Item = i32>>。但是当 Animal 有不同种类的 Food.

时,它并没有解决问题

² 通过编译时多态性(泛型),您可以编写泛型代码,覆盖任何实现 Animal 和任何 Food 类型的代码。但是你不能将不同编译时类型的东西放在 Vec 中,所以这也无济于事。