特征中具有关联类型的多态结构向量
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>`
但在这种情况下,我不能只遵循错误消息,因为实现特征 Animal
的 struct
的数量不应该是静态的。
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
中,所以这也无济于事。
我想了解 多态性 在使用具有关联类型 的特征时如何工作 。考虑以下特征:
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>`
但在这种情况下,我不能只遵循错误消息,因为实现特征 Animal
的 struct
的数量不应该是静态的。
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
中,所以这也无济于事。