考虑以下愚蠢的例子:
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
中,因为我在编译时不知道它的大小。它可以包裹在任何类型的Attraction
和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
中,就像我在这里一样。
我知道有类型擦除,这意味着我只会返回ThemePark
而不是SeriousThemePark
,但这就足够了。
我在这里使用的特质是错的吗?你会怎么去解决这个问题。来自Java / Scala / C ++我似乎对现有思维过于深入。
答案 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抱歉!)和一种访客(只有老年人,没有老年女士或儿童)。