如何为类似的匹配武器编写宏?

时间:2017-05-17 19:25:25

标签: rust

我有一些重复的代码

match *x {
    A(ref a) => "special",
    B(ref a) => "B foo",
    C(ref a) => "C foo",
    D(ref a) => "D foo",
    // ...
}

我想要像

这样的宏
macro_rules! generic_fmt {
    ($T:ident) => {
        $T(ref a) => {"$T foo"},
    }
}

这样我就可以简化我的匹配

match *x {
    A(ref a) => "special",
    generic_fmt!(B),
    generic_fmt!(C),
    generic_fmt!(D),
    // ...
}

最好的方法是什么?我每晚都在使用rustc 1.19.0。

2 个答案:

答案 0 :(得分:2)

如果稍微改变你的输出是可以接受的,那么你可以对所有相同的武器使用全能:

match x {
    Foo::A(ref a) => println!("special"),
    _ => println!("{:?} Foo", x),
}

Playground link

但这会打印出类型及其参数。如果你在夜间,而不是害怕实验,你可以使用std::intrinsics::type_name只显示类型名称。

或者你可以使用一个可以完成所有匹配的宏:

macro_rules! gen_match {
    ($x:ident, $Special:ident, [$( $Foo:ident ),*]) => {
        match $x {
            Foo::$Special(ref a) => println!("special"),
            $(Foo::$Foo(ref a) => println!("{} foo", stringify!($Foo)),)*
        }
    }
}

并称之为:

gen_match!(x, A, [B, C, D]);

Playground link

通用格式的变体周围的括号是为了便于阅读,可以从宏定义中删除它们

答案 1 :(得分:1)

你不能完全这样做。宏无法扩展为<Variant> => <Expression>分支(enum Foo { A(u32), B(u32), C(u32), D(u32), } macro_rules! gen1 { ($Variant:ident) => { Foo::$Variant(ref a) } } macro_rules! gen2 { ($Variant:ident) => { concat!(stringify!($Variant), " foo") } } fn print(x: Foo) { println!("{}", match x { Foo::A(ref a) => "special", gen1!(B) => gen2!(B), gen1!(C) => gen2!(C), gen1!(D) => gen2!(D), }); } fn main() { print(Foo::A(42)); print(Foo::B(42)); print(Foo::C(42)); print(Foo::D(42)); } )。

你最接近的可能是这样的:

brew.sh

Playground link.