当每个臂返回类型与类型参数的不同组合时,如何减少 2 个嵌套匹配语句

问题描述 投票:0回答:1

我的问题:我有一个返回

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 个参数的函数。但由于参数的每个组合都会返回不同的类型,我很困惑!

编辑:一揽子实施在这种情况下会有任何帮助吗?

(如果有人有更好的方式来表达我的问题,请随时纠正我!)

generics rust nested match
1个回答
0
投票

一点类型元编程可以在这里提供帮助。

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!(),
    }
}

游乐场

我们基本上创建一个类型工厂,为内部类型创建外部类型。然后我们有一个函数根据这个类型级工厂做出运行时决策,剩下要做的就是有一个函数在每个工厂中调用这个函数。

© www.soinside.com 2019 - 2024. All rights reserved.