如何创建异构的对象集合?

问题描述 投票:11回答:1

我想在Vec中使用特征对象。在C ++中,我可以创建一个基类Thing,从中导出Monster1Monster2。然后我可以创建一个std::vector<Thing*>Thing对象必须存储一些数据,例如x : int, y : int,但派生类需要添加更多数据。

目前我有类似的东西

struct Level {
    // some stuff here
    pub things: Vec<Box<ThingTrait + 'static>>,
}

struct ThingRecord {
    x: i32,
    y: i32,
}

struct Monster1 {
    thing_record: ThingRecord,
    num_arrows: i32,
}

struct Monster2 {
    thing_record: ThingRecord,
    num_fireballs: i32,
}

我用ThingTraitget_thing_record()attack()等方法定义了make_noise(),并为Monster1Monster2实现它们。

rust
1个回答
17
投票

Trait objects

实现对象的异构集合(在本例中为向量)的最可扩展方式正是您所拥有的:

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等都是特质对象。这些允许在无数种类型上实现特征,但权衡是需要一定量的间接和动态调度。

也可以看看:

Enums

正如评论中所提到的,如果您有固定数量的已知替代方案,那么开放性较低的解决方案就是使用枚举。这不要求值为Boxed,但它仍然会有少量的动态调度来决定运行时存在哪个具体的枚举变量:

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)];
}
© www.soinside.com 2019 - 2024. All rights reserved.