Rust 如何为相似的匹配臂编写宏?

Rust 如何为相似的匹配臂编写宏?,rust,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",
    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。

你不能完全做到这一点。宏无法展开为匹配的臂(
=>

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

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));
}

你不能完全做到这一点。宏无法展开为匹配的臂(
=>

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

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));
}

如果可以稍微更改输出,则可以对所有相同的手臂使用“全部捕捉”:

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

但这将打印类型及其参数。如果您每晚都在使用,并且不怕实验,则可以使用仅显示类型名称

或者,您可以使用宏来执行所有匹配臂:

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]);


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

如果可以稍微更改输出,则可以对所有相同的臂使用“全部捕捉”:

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

但这将打印类型及其参数。如果您每晚都在使用,并且不怕实验,则可以使用仅显示类型名称

或者,您可以使用宏来执行所有匹配臂:

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]);


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

如何使用
type_name
?它只给出
枚举的类型
,而不是单个项目?哦
type_name
不像我想象的那样适用于
Enum
。。。你可以试试,写这本书很有趣。我该如何使用
键入\u name
?它只给出
枚举的类型
,而不是单个项目?哦
type_name
不像我想象的那样适用于
Enum
。。。你可以试试,写起来很有趣