考虑以下简化的示例:
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
因为我在编译时不知道它的大小。它可以包裹在任何类型的Attraction
and周围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++,我似乎在现有的思维中陷入了太深的困境。