我正在尝试创建一个生成 struct
的宏,它提供了一组传递给宏的方法 . 例如,调用:
create_impl!(StructName, fn foo() -> u32 { return 432 })
应该生成一个提供方法 foo()
的空结构 StructName
.
我最初尝试使用 item
宏arg类型 . 但是,当我尝试在规则中使用 item
时,我收到以下编译器错误:
error: expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `fn foo() -> u32 { return 42; }`
--> src/lib.rs:40:13
|
40 | $($function)*
| ^^^^^^^^^
是否可以使用 item
参数以这种方式定义生成的结构中的方法?有什么我想念的吗?
这是我定义的完整宏:
macro_rules! create_impl {
($struct_name:ident, $($function:item),*) => {
struct $struct_name {
}
impl $struct_name {
// This is the part that fails.
$($function)*
}
};
}
1 回答
简短的回答是“不,你不能使用
item
matcher作为方法” .根据reference,项目是包或模块中的顶级事物,因此功能,类型等等 . 虽然
struct
或impl
块是一个项目,但它们内部的东西不是't. Even though syntactically, a method definition looks identical to a top level function, that doesn' t使它成为一个项目 .Rust的宏系统的工作方式是,一旦片段被解析为
item
,例如使用$foo:item
,它永远是item
;一旦宏扩展,它就会被拆分成令牌以进行重新分析 .结果是
$foo:item
只能在项目位置的宏输出中,这通常意味着顶级 .有几种选择 .
最简单的是使用好的旧
tt
(标记树)匹配器 . 标记树是非括号标记或由 balancer 括号包围的标记序列;所以$(foo:tt)*
匹配任何东西 . 但是,这意味着它也会吞噬逗号,所以在每个项目周围添加大括号更容易:macro_rules! create_impl {
然后你必须使用额外的括号:
您也可以直接匹配所需的语法,而不是委托给
item
匹配器:当然,因为它是显式的,这意味着如果你想支持没有返回类型的函数,你需要为宏添加另一个案例 .