Macros 是否可以定义一个宏,从数字生成所有枚举值的静态数组?

Macros 是否可以定义一个宏,从数字生成所有枚举值的静态数组?,macros,rust,Macros,Rust,我想写这段代码: enum Foo { A1 = 1, A17 = 17, A42 = 42, } static FOO_VALUES: [Foo; 3] = [Foo::A1, Foo::A17, Foo::A42]; impl Foo { fn to_num(self) -> i32 { match self { Foo::A1 => 1, //... }

我想写这段代码:

enum Foo {
    A1 = 1,
    A17 = 17,
    A42 = 42,
}

static FOO_VALUES: [Foo; 3] = [Foo::A1, Foo::A17, Foo::A42];

impl Foo {
    fn to_num(self) -> i32 {
        match self {
            Foo::A1 => 1,
            //...
        }
        fn from_num(a: i32) -> Result<Foo, ()> {
            //...
        }
    }
}
宏的用法类似于
define\u foo\u enum!(1, 17, 42);

我想这段代码不会编译,因为
concat\ident无法以我尝试使用它的方式工作。此外,我正在为宏提供数字,而不是标识符,但我不知道使用什么类型,
tt

我使用的是Rust 1.17。

我的板条箱可以像您预期的那样形成串联标识符。自1.15以来,它支持任何稳定的Rust编译器,尽管在下面的实现中,我使用了一个需要Rust 1.20+的相关常量

#[macro_use]
extern crate mashup;

macro_rules! define_foo_enum {
    ($name:ident { $($number:tt),* }) => {
        mashup! {
            $(
                m["A" $number] = A $number;
            )*
        }
        m! {
            #[derive(Debug, PartialEq)]
            pub enum $name {
                $(
                    "A" $number,
                )*
            }
            impl $name {
                pub const VALUES: &'static [Self] = &[$($name::"A" $number,)*];
            }
        }
    }
}

define_foo_enum!(Foo { 1, 17, 42 });

fn main() {
    assert_eq!(Foo::VALUES, [Foo::A1, Foo::A17, Foo::A42]);
}

注意:
to_num(self)
可以写成
self as i32
。显然,反向转换并不容易,因为并非所有整数都是有效值。此外,您还可以使用
#[repr(i32)]
强制编译器了解
Foo
在内存中的表示方式,从而允许
transmute
用于反向转换。@MatthieuM。事实上,主要功能是所有值的数组(
ITEMS
),从/到i32并不重要,至少
mactch
rustc
可以控制我在匹配中提到所有值,但手工定义的数组只能有几个匹配值,编译器对此不作任何报告。@user1244932您的意思是
concat_idents@肯尼特:我需要像
concat\n这样的东西,不完全是它
#[macro_use]
extern crate mashup;

macro_rules! define_foo_enum {
    ($name:ident { $($number:tt),* }) => {
        mashup! {
            $(
                m["A" $number] = A $number;
            )*
        }
        m! {
            #[derive(Debug, PartialEq)]
            pub enum $name {
                $(
                    "A" $number,
                )*
            }
            impl $name {
                pub const VALUES: &'static [Self] = &[$($name::"A" $number,)*];
            }
        }
    }
}

define_foo_enum!(Foo { 1, 17, 42 });

fn main() {
    assert_eq!(Foo::VALUES, [Foo::A1, Foo::A17, Foo::A42]);
}