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

ste*_*era 11 rust

我想在一个中使用特征对象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,
}
Run Code Online (Sandbox Code Playgroud)

我定义了一个ThingTrait与方法get_thing_record(),attack(),make_noise()等,并实现它们的Monster1Monster2.

She*_*ter 17

特质对象

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

Vec<Box<dyn ThingTrait + 'static>>
Run Code Online (Sandbox Code Playgroud)

虽然有些时候你可能想要一辈子没有'static,所以你需要这样的东西:

Vec<Box<dyn ThingTrait + 'a>>
Run Code Online (Sandbox Code Playgroud)

您还可以拥有对特征的引用集合,而不是盒装特征:

Vec<&dyn ThingTrait>
Run Code Online (Sandbox Code Playgroud)

一个例子:

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)];
}
Run Code Online (Sandbox Code Playgroud)

Box<SomeTrait>,Rc<SomeTrait>,&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)];
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,枚举采用其最大选项的大小。如果您的 Monster 还具有一个大型数组选项,则向量中的每个 Monster 实例都将具有该大型数组的内存占用量。 (4认同)