特质对象
实现一个异构对象集合(在本例中为向量)最具可扩展性的方式就是使用您已经拥有的方法:
Vec<Box<dyn ThingTrait + 'static>>
虽然有时候你可能需要一个不是 'static
的生命周期,那么你就需要像这样的东西:
Vec<Box<dyn ThingTrait + 'a>>
你也可以拥有一个对特质的
引用集合,而不是装箱特质:
Vec<&dyn ThingTrait>
一个例子:
trait ThingTrait {
fn attack(&self);
}
impl ThingTrait for Monster1 {
fn attack(&self) {
println!("monster 1 attacks")
}
}
impl ThingTrait for Monster2 {
fn attack(&self) {
println!("monster 2 attacks")
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things: Vec<Box<dyn ThingTrait>> = vec![Box::new(m1), Box::new(m2)];
}
Box<dyn SomeTrait>
、Rc<dyn SomeTrait>
、&dyn SomeTrait
等都是特质对象。这些允许在无限数量的类型上实现特质,但代价是需要一定程度的间接性和动态分派。
另请参见:
枚举
正如评论中提到的,如果你有一个固定数量的已知选择,一个不那么开放式的解决方案是使用枚举。这不要求值被Box
包装,但它仍然需要一小部分动态分派来决定运行时存在哪个具体枚举变量:
enum Monster {
One(Monster1),
Two(Monster2),
}
impl Monster {
fn attack(&self) {
match *self {
Monster::One(_) => println!("monster 1 attacks"),
Monster::Two(_) => println!("monster 2 attacks"),
}
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things = vec![Monster::One(m1), Monster::Two(m2)];
}
另请参阅: