我想使用宏创建匹配。我不知道该怎么做,因为我似乎错过了宏如何处理元素列表(或者也许我做错了其他事情)。 我的用例:我有 N 个通用类型,例如
MyStructA<X: MyTraitTwo>, MyStructB<X: MyTraitTwo>, MyStructC<X: MyTraitTwo>
(实现了特征TraitOne
),我使用泛型类型作为参数X。我想要有N个匹配臂(对于每个结构MyStruct?
)。我的实际用例有嵌套匹配,例如X 的 M 种不同类型。因此,我必须手动编写 N * M 匹配臂。但首先是非嵌套的情况:
fn create_type(arg: &str) -> impl MyTrait {
make_match_arms![("a", MyStructA),("b", MyStructB), ("c", MyStructC)];
}
// would expand to:
fn create_type(arg: &str) -> impl MyTraitOne {
match => arg {
"a" => MyStructA<X>::new(),
"b" => MyStructB<X>::new(),
"c" => MyStructC<X>::new(),
}
}
理想情况下,我什至可以将其简化为两个类型列表,并将其提供给宏,该宏将为这两个元素的每个组合创建匹配臂。像这样(我省略了泛型,因为我不确定它们是否可以使用)。
match (first_type_str, second_type_str) => {
every_combination![(MyStructA, MyStructB, MyStructC), (X1, X2, X3, X4, X5)]
};
它看起来像这样:
fn return_combined_type(first: &str, second: &str) -> impl TraitOne<TraitTwo> {
match first => {
"a" => {
match second => {
"1" => {MyStructA::<X1>::new(),
"2" => {MyStructA::<X2>::new(),
...
},
"b" => {
match second => {
"1" => { MyStructB::<X1>::new(),
...
...
这将创建 15 个火柴臂 - 嵌套在 2 个火柴中。当然,我必须提供一个论点,即手臂与 (
first
, second
) 也与宏相匹配,但我现在不确定如何执行此操作。
我不确定我是否能正确解释这一点。也许有人能够读懂字里行间并理解我的问题。
这是一个部分答案,使用重复,仅涵盖您问题的第一部分:
#[allow(unused)]
fn main() {
macro_rules! make_match_arms {
($arg:expr, $(($s:literal, $id:ident)),*) => {
{match $arg {
$(
$s => Box::new($id::<X>::new()),
)*
_ => panic!()
}}
}
}
struct MyStructA<T>(T);
struct MyStructB<T>(T);
struct MyStructC<T>(T);
impl<T: Default> MyStructA<T> { fn new() -> Self { Self(Default::default()) } }
impl<T: Default> MyStructB<T> { fn new() -> Self { Self(Default::default()) } }
impl<T: Default> MyStructC<T> { fn new() -> Self { Self(Default::default()) } }
trait MyTrait {}
impl<T> MyTrait for MyStructA<T> {}
impl<T> MyTrait for MyStructB<T> {}
impl<T> MyTrait for MyStructC<T> {}
fn create_type<X: Default + 'static>(arg: &str) -> Box<dyn MyTrait> {
make_match_arms![arg, ("a", MyStructA),("b", MyStructB), ("c", MyStructC)]
}
}
我不知道宏有什么方法可以从两个列表自动生成每个组合,所以我看不到不涉及冗余的第二部分的答案。