Rust子类型/"运行时多态性" /使用Box中的特征

时间:2018-01-03 14:39:53

标签: rust polymorphism subtyping

考虑以下愚蠢的例子:

pub trait ThemePark<A, V>
where
    A: Attraction,
    V: Visitor,
{
    fn create(square_size: u32, name: &str) -> Self;
    fn get_attractions(&self) -> Vec<A>;
    fn get_visitors(&self) -> Vec<V>;
}

pub trait Attraction {}
pub trait Visitor {}

具体的ThemePark可以拥有任意一组景点以及访客。它们用结构体实现:

struct ElderlyWhiteMale;
impl Visitor for ElderlyWhiteMale {}

ThemePark包含在某些公司的资产中,如下所示:

pub struct Asset<'a> {
    name: &str,
    theme_park: Box<ThemePark<> + 'a> // <-- This won't compile, as ThemePark needs 2 type arguments
}

这开始了我的痛苦。我将ThemePark放在Box中,因为我在编译时不知道它的大小。它可以包裹在任何类型的AttractionVisitor

ThemePark需要2个类型参数,但我无法在编译时知道它们。在我的代码中的某处,我从外部文件中读取此内容并相应地构建ThemePark

我的想法是,在运行时我可以从外部源创建ThemePark,然后调用其上的特征中定义的functions

impl Asset {
    fn init_and_query() -> () {
        let theme_park: Box<ThemePark> = match external_file.get_theme_park_type {
            ThemeParkType::FUN => unimplemented! {"There is no fun, yet!"},
            ThemeParkType::SERIOUS => {
                println!("Creating serious themepark");

                SeriousThemePark::create(size /*...*/)
            }
        };

        let attractions = theme_park.get_attractions();
        // ... Do something with the attractions
    }
}

pub enum ThemeParkType {
    FUN,
    SERIOUS,
}

我知道我无法将ThemePark原样放在堆栈上......它的大小在编译时是未知的,所以编译器不知道是什么分配。

这就是为什么我要使用引用&或将其包装在Box中,就像我在这里一样。

我知道有类型擦除,这意味着我只会返回ThemePark而不是SeriousThemePark,但这就足够了。

我在这里使用的特质是错的吗?你会怎么去解决这个问题。来自Java / Scala / C ++我似乎对现有思维过于深入。

1 个答案:

答案 0 :(得分:3)

在这方面,Rust多态性与C ++多态性非常相似;它的特点:

  • 编译时多态,用于参数化具有编译时已知类型的项目
  • 运行时多态,当在编译时不知道具体类型时。

Rust使用trait来定义接口,然后用于约束编译时类型参数并充当运行时多态的基类/接口,这可能是你的困惑来自哪里,但是这两种多态性本质上是不同的。

pub struct Asset<'a> {
    name: &str,
    theme_park: Box<ThemePark<> + 'a> // <-- This won't compile, as ThemePark needs 2 type arguments
}

然后你不应该使用编译时多态,而是将ThemePark定义为:

pub trait ThemePark {
    fn create(square_size: u32, name: &str) -> Self;
    fn get_attractions(&self) -> Vec<Box<Attraction>>;
    fn get_visitors(&self) -> Vec<Box<Visitor>>;
}

通过实例化ThemePark<A, V>,您可以创建一个只能包含一种景点的主题公园(这里所有的鬼屋,没有Flume Ride抱歉!)和一种访客(只有老年人,没有老年女士或儿童)。