我的问题:我有一个返回
Box<dyn Trait_1>
对象的函数。假设我在第 1 层有 N=2
可能的类型来实现这个 Trait_1
并且我希望这两种类型都可以通过 match 语句访问。但现在这 2 种可能的类型也是通用的(但必须实现 Trait_2
),并且我想在第 2 级使用 M=2
可能的类型。现在,我可以进行一场 4 个手臂的比赛,也可以进行 2 个嵌套的比赛,每个比赛有 2 个手臂。我必须编写 4 条语句来初始化这个Box
。这很简单。但是,如果我在第 1 级有 N=15
类型(实现 Trait_1),在第 2 级有 20 个类型,实现其他一些 Trait_2
,我最终会编写 300 个不同的初始化!这是很多工作,而且我可能会犯一些错误。
我已经用 2 个嵌套的匹配语句编写了一个简单的问题示例,每个语句都有 2 个分支,总共导致 4 次初始化(我省略了 Trait 实现)
pub trait Trait_1 {}
pub trait Trait_2 {}
pub struct SingleContainer<T: Trait_2> {
item: T,
}
pub struct DoubleContainer<T: Trait_2> {
item_1: T,
item_2: T,
}
// -> impl Trait_1 for SingleContainer and DoubleContainer
struct X {
number: f64,
}
struct Y {
number: u32,
}
// -> impl Trait_2 for X and Y
fn main() {
let a = // determined at runtime
let b = // determined at runtime
let thing = give_thing(a, b);
}
fn give_thing(thing_number: usize, thing_name: &str) -> Box<dyn Trait_1> {
match thing_number {
1 => match thing_name {
"X" => Box::new(SingleContainer::<X>::default()),
"Y" => Box::new(SingleContainer::<Y>::default()),
_ => todo!(),
},
2 => match thing_name {
"X" => Box::new(DoubleContainer::<X>::default()),
"Y" => Box::new(DoubleContainer::<Y>::default()),
_ => todo!(),
},
_ => todo!(),
}
}
有更好的方法吗?我很难以另一种方式看待,因为每种事物都是不同的类型。我希望在编译时(SingleContainer,DoubleContainer)和(X,Y)的每个可能组合“存在”,因此将被优化。如果有更好的方法来实现这一目标,请告诉我!我基本上只需要一个返回
Box<dyn MyTrait>
对象并获取 2 个参数的函数。但由于参数的每个组合都会返回不同的类型,我很困惑!
编辑:一揽子实施在这种情况下会有任何帮助吗?
(如果有人有更好的方式来表达我的问题,请随时纠正我!)
一点类型元编程可以在这里提供帮助。
trait MakeTrait1 {
type Make<T: Trait_2 + Default + 'static>: Trait_1 + Default + 'static;
}
struct MakeSingleContainer;
impl MakeTrait1 for MakeSingleContainer {
type Make<T: Trait_2 + Default + 'static> = SingleContainer<T>;
}
struct MakeDoubleContainer;
impl MakeTrait1 for MakeDoubleContainer {
type Make<T: Trait_2 + Default + 'static> = DoubleContainer<T>;
}
fn make_trait1<T: MakeTrait1>(thing_name: &str) -> Box<dyn Trait_1> {
match thing_name {
"X" => Box::new(T::Make::<X>::default()),
"Y" => Box::new(T::Make::<Y>::default()),
_ => todo!(),
}
}
fn give_thing(thing_number: usize, thing_name: &str) -> Box<dyn Trait_1> {
match thing_number {
1 => make_trait1::<MakeSingleContainer>(thing_name),
2 => make_trait1::<MakeDoubleContainer>(thing_name),
_ => todo!(),
}
}
游乐场。
我们基本上创建一个类型工厂,为内部类型创建外部类型。然后我们有一个函数根据这个类型级工厂做出运行时决策,剩下要做的就是有一个函数在每个工厂中调用这个函数。