Ответ 1
Черты объектов
Самый расширяемый способ реализации гетерогенной коллекции (в данном случае вектора) объектов - это именно то, что у вас есть:
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<SomeTrait>
, Rc<SomeTrait>
, &SomeTrait
и т.д. Являются объектами признаков. Они позволяют реализовать эту черту для бесконечного числа типов, но компромисс заключается в том, что она требует некоторой косвенности и динамического распределения.
Смотрите также:
Перечисления
Как упоминалось в комментариях, если у вас есть фиксированное количество известных альтернатив, менее открытым решением является использование enum. Это не требует, чтобы значения были Box
ed, но он все равно будет иметь небольшую динамическую диспетчеризацию, чтобы решить, какой конкретный вариант enum присутствует во время выполнения:
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)];
}