是否可以使用定义为宏参数的字段在Rust宏内构建枚举?我试过这个:
macro_rules! build {
($($case:ty),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
但它失败了error: expected ident, found 'Foo(i32)'
请注意,如果字段是在枚举中定义的,则没有问题:
macro_rules! build {
($($case:ty),*) => { enum Test { Foo(i32), Bar(i32, i32) } };
}
fn main() {
build!{ Foo(i32), Bar(i32, i32) };
}
如果我的宏只接受简单字段,它也有效:
macro_rules! build {
($($case:ident),*) => { enum Test { $($case),* } };
}
fn main() {
build!{ Foo, Bar };
}
但是我在一般情况下无法让它工作。
答案 0 :(得分:8)
这绝对可能,但你把完全不相关的概念混为一谈。
$case:ty
之类的内容并不意味着$case
是看起来类似的内容,这意味着$case
字面上 a类型。枚举不是由一系列类型组成的;它们由一系列变体组成,它们是一个标识符,后跟(可选)由元组结构体,记录结构体或标记值组成。
解析器并不关心你给它的类型是否恰巧看起来就像一个有效的变种,它只是不期望一个类型,并且会拒绝在那个位置解析一个。
您需要使用$case:variant
之类的东西。不幸的是,没有这样的匹配器。做这样的事情的唯一方法是使用递归增量解析器手动解析它,并且所以超出SO问题的范围这是不好笑的。如果您想了解更多信息,请尝试chapter on incremental TT munchers in the Little Book of Rust Macros作为起点。
但是,您似乎没有实际对案例做任何事情。你只是盲目地代替他们。在这种情况下,你可以欺骗,而不是试图匹配任何连贯的东西:
macro_rules! build {
($($body:tt)*) => {
as_item! {
enum Test { $($body)* }
}
};
}
macro_rules! as_item {
($i:item) => { $i };
}
fn main() {
build!{ Foo, Bar };
}
(顺便提一下,在AST coercion( a.k.a。“重新分析技巧”)一节中解释了as_item!
事。)
这只是抓取作为build!
的输入提供的所有内容,并将其推入enum
的正文中,而不关心其外观。
如果您尝试使用变体做一些有意义的,那么,您将不得不be more specific about what you're actually trying to accomplish,因为关于如何进行的最佳建议会因狂野而变化取决于答案。