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

5

注意:此问题针对的是Rust 1.0版本之前的一个功能,该功能已从语言中删除。


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

我有LocalPlayerNetPlayer结构体,它们都实现了Inputable特征,并继承了虚拟结构体Player中的player_num字段。根据游戏开始的方式,我的程序中的player_2可以是LocalPlayerNetPlayer。根据不同的情况,Inputable特征的实现方式也会发生改变。

编译器不允许我根据player_2NetPlayer还是LocalPlayer来动态分配类型。它报错如下:

error: mismatched types: expected ~player::LocalPlayer but found ~player::NetPlayer (expected struct player::LocalPlayer but found struct player::NetPlayer)

它也不允许我将NetPlayerLocalPlayer指针强制转换为Player指针。因为它们不是可扩展的。

涉及到的代码示例如下:

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;

1
自从Rust有了虚拟结构体和结构体继承?哦,据我所知,这方面的各种RFC仍然悬而未决。 - Vladimir Matveev
@VladimirMatveev:据我所知,这是一个部分实现的功能,目前还不能完成所要求的操作。 - Chris Morgan
1
我正在使用 #![feature(struct_inherit)] 的实验功能。 - Suraj
@ChrisMorgan,这很奇怪,它根本没有被宣传。 - Vladimir Matveev
@VladimirMatveev:这是有原因的。 - Chris Morgan
3个回答

6

Rust中的结构体继承非常原始,你可能不想使用它。在Rust中,继承结构体之间没有子类型或强制转换。该特性基本上只允许您在有许多具有相似字段的结构体时节省打字(这也为将来可能添加围绕它们的更多功能做好了准备)。

你可以创建PlayerLocalPlayerNetPlayer特质。然后你就可以在它们之间获得所需的子类型行为。或者,你可以只创建LocalPlayerNetPlayer 结构体,并让 Player 成为一个特质。甚至还可以有一个PlayerImpl结构体,你可以从当前的方式继承它(如果你有许多要共享的字段),但你需要为两个结构体编写独立的impls。


但是假设我只想使用结构体继承来“嵌入”父结构体中的字段到子结构体中。实际上,我确实想要原始结构体继承。我该怎么做呢?关于这个问题没有任何文档可以查找。 - TobTobXX

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 解决方案(例如在 traits 或结构体中使用 getters/setters 或枚举)。

4

最终我使用枚举类型实现了Player

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

每次调用共享函数时,我需要执行以下操作:
let input = match player2 {
    player::Net(player) => player.get_input(),
    player::Local(player) => player.get_input(),
};

12
你可以在枚举上实现方法,例如:impl Player { fn get_input(&self) -> ? { match *self { Net(ref player) => player.get_input(), Local(ref player) => player.get_input() } } } - Chris Morgan
太棒了,我不知道! - Suraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接