如何进行类型转换和继承Rust结构?

时间:2014-05-13 06:14:14

标签: struct rust

我正在使用实验性功能feature(struct_inherit)

我有LocalPlayerNetPlayer结构,它们都实现Inputable特征,并从虚拟结构player_num继承Player字段。根据游戏的开始方式,我的计划中的player_2可以是LocalPlayerNetPlayer。具体取决于哪一个,Inputable特征的实施方式发生了变化。

编译器不允许我动态分配player_2类型,具体取决于它是NetPlayer还是LocalPlayer。它抱怨道:

  

错误:不匹配的类型:期望~player::LocalPlayer但找到~player::NetPlayer(预期的struct player :: LocalPlayer但找到struct player :: NetPlayer)

它还不允许我对NetPlayer指针进行类型转换LocalPlayerPlayer指针。它声称它们不具备可扩展性。

有问题的代码示例如下:

let player1 = box player::LocalPlayer::new(0);
let player2;
if local {
    player2 = box player::LocalPlayer::new(1);
} else if hosting {
    player2 = box player::NetPlayer::new(1);
    player2.host();
} else {
    player2 = box player::NetPlayer::new(1);
    player2.connect();
}
/* ... Omitted Code ... */
let input = player2.get_input(); // Trait function

结构实现如下:

pub virtual struct Player {
    player_num: uint
}
pub struct LocalPlayer: Player;
pub struct NetPlayer: Player;

3 个答案:

答案 0 :(得分:5)

Rust中的结构继承非常原始;你可能不想使用它。在Rust中继承结构之间没有子类型或强制。如果你有很多具有类似字段的结构,这个功能基本上只允许你保存输入(它还可以为将来在它们周围添加更多功能而进行未来验证)。

您可以制作PlayerLocalPlayerNetPlayer个特征。然后,您可以获得它们之间所需的子类型行为。或者,您可以只生成LocalPlayerNetPlayer结构,让Player成为特征。您甚至可以拥有一个PlayerImpl结构,您可以从当前的方式继承该结构(如果您要分享很多字段),但是您需要为两个结构编写独立的impls。

答案 1 :(得分:4)

Rust的特征与接口类似,可以组成模拟接口层次结构。它们通常是继承的替代品:

trait GetInput {
    fn get_input(&self);
}

impl GetInput for Player {
    fn get_input(&self) {}
}

impl GetInput for NetPlayer {
    fn get_input(&self) {}
}

// Fast: interface selected at compile time
fn do_something<T: GetInput>(player: T) {
    player.get_input();
}

// Flexible: interface selected at run time (virtual call)
// Use with Box<Player> (see "Trait Objects")
fn do_something_dyn(player: &dyn GetInput) {
    player.get_input();
}

但是,Rust没有继承数据。要在类型之间共享公共字段,您需要一些替代的DIY解决方案(例如特征中的getter / setter或带有枚举的结构)。

答案 2 :(得分:3)

我最终将Player作为枚举实现:

pub enum Player {
    Net(NetPlayer),
    Local(LocalPlayer)
}

每次调用共享函数时,我都需要执行以下操作:

let input = match player2 {
    player::Net(player) => player.get_input(),
    player::Local(player) => player.get_input(),
};