提到通用对象的特征似乎是不可能的

时间:2014-08-12 10:57:47

标签: rust

考虑以下简单结构:

struct Monster {
    // ...
}

struct Player {
    // ...
}

struct Missile {
    // ...
    //target: ???,
}

在编写游戏逻辑时,让对象相互引用是很常见的。在上面的示例中,我们使用结构MonsterPlayerMissile来说明所需的交互类型。

想象一下,我们有以下特征:PositionThink。以上所有结构都实现了Position,除了Missile之外的所有结构都实现了Think

首先要注意的是Missile是一种归航导弹:它存储一个目标,每当游戏更新Missile个物体时,它就会将它移向它的目标。

据我所知,不可能在Rust中合理地存储此Missile的目标。

显然,导弹没有自己的目标。它只是想访问其Position特征。必须通过RcGc分享游戏对象。但它不像Missile只能存储Weak<???>引用具有Position特征的内容。 Box<Position>意味着消耗具有该特征的任何对象。 Box<Any>不允许向下转换为特征。

制作Missile<T>并将目标存储为Weak<T>无济于事。那些Missile<T>将如何存储?导弹所针对的每种物体都有一个Collection<T>?游戏对象需要更通用,而可怕的Box<Any>似乎是不可避免的。

我对Rust很新。令我感到困惑的是,这是不可能的。当然,我一定错过了什么?

1 个答案:

答案 0 :(得分:4)

我也是Rust的新手,但这就是我发现的。您可以将std::rc::Rc<T>结构与Box结合使用。要拥有可变的共享引用,您需要在std::cell::RefCell

中包装盒装项

所以,你的玩家,怪物,导弹示例会是这样的:

use std::cell::RefCell;
use std::rc::Rc;

trait Position {
    fn position(&mut self);
}

struct Monster;

impl Position for Monster {
    fn position(&mut self) {
        println!("Rawr I am getting the monster's position");
    }
}

struct Player {
    x: i32,
}

impl Position for Player {
    fn position(&mut self) {
        println!("Getting player's position {}", self.x);
        self.x += 1;
    }
}

struct Missile {
    target: Rc<RefCell<Box<Position>>>,
}

fn main() {
    // Create some stuff
    let player = Rc::new(RefCell::new(Box::new(Player{x: 42}) as Box<Position>));
    let monster = Rc::new(RefCell::new(Box::new(Monster) as Box<Position>));

    // Our missile: initial target - monster
    let mut missile = Missile{target: monster};

    // Should be a monster
    missile.target.borrow_mut().position();

    // Redirect missile to player
    missile.target = player.clone();

    // Should be a player
    missile.target.borrow_mut().position();

    // Show that it is in fact a reference to the original player
    player.borrow_mut().position();
}

但是,通常可以设计不需要共享引用的实体系统,这被认为是更惯用的Rust。如果您的实体系统非常复杂,我建议使用实体组件系统。

编辑:改进了代码和信息,并删除了一些不准确的信息。