我想写这段代码:
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, ()> {
//...
}
}
}
为了防止错误,我想用宏生成代码:
macro_rules! define_foo_enum {
($Name:ident { $($Variant:ident),* }) => {
pub enum $Name {
$(concat_ident!(A, $Variant)),*,
}
const concat_indent!($Name, _VALUES): &'static [$Name] = &[$($Name::concat_ident!(A, $Variant)),*];
}
}
宏将像define_foo_enum!(1, 17, 42);
这段代码无法编译,我想因为concat_ident!
不能按照我尝试使用它的方式工作。另外,我正在为宏提供数字,而不是标识符,但我不知道要使用哪种类型,tt
?
我正在使用Rust 1.17。
答案 0 :(得分:3)
我的mashup
板条箱可以像您期望的那样形成连接的标识符。自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]);
}