1

考虑以下简化的示例:

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 {}

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

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

这开始了我的痛苦。我放ThemePark了 aBox因为我在编译时不知道它的大小。它可以包裹在任何类型的Attractionand周围Visitor

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

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

我在这里使用的特征都错了吗?你会怎么去解决这个问题。来自 Java/Scala/C++,我似乎在现有的思维中陷入了太深的困境。

4

1 回答 1

4

在这方面,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!)和一种类型的游客(只有老人在,没有老人女士或孩子)。

于 2018-01-03T14:51:21.540 回答