Rust中外部macro_rules定义的内部宏能否使用重复语法?嵌套宏编写报错求助
Rust中外部macro_rules定义的内部宏能否使用重复语法?嵌套宏编写报错求助
嗨,这个问题我之前也踩过同款坑!你碰到的错误,根源是Rust的macro_rules解析器处理嵌套宏时的一个“小脾气”:当你在外部宏里定义内部宏时,内部宏里的重复语法(比如$(#[$attrs:meta])*)会被外部宏的解析器当成自己的重复结构来处理,但你的外部宏模式里只定义了$variant和$t这两个重复变量,完全没用到$attrs,外部宏直接就懵了——它觉得你在重复一个没有对应重复变量的内容,所以直接抛出错误。
那怎么解决呢?其实很简单,给内部宏的重复结构套一层“空的重复外壳”,让外部宏把它当成普通的token流原封不动传给内部宏就行。我给你修正了代码,直接就能跑:
macro_rules! define_enum_definer { { $($variant: ident => $t: ty,)+ } => { macro_rules! define_enum { // 把原来的 $(#[$attrs:meta])* 改成 $($(#[$attrs:meta])*)* ($($(#[$attrs:meta])*)* $name: ident($container: ident)) => { // 这里也要对应改成 $($(#[$attrs:meta])*)* $($(#[$attrs:meta])*)* enum $name { $($variant($container<$t>),)+ } }; } }; } define_enum_definer! { I32 => i32, I64 => i64, } define_enum!( #[derive(Clone, Debug)] #[non_exhaustive] DynTypedVec(Vec) ); fn main() { let x = DynTypedVec::I32(vec![1, 2, 3]); println!("{:?}", x); }
运行这段代码就能正常输出I32([1, 2, 3])了!
我再给你唠唠为啥这么改能行:原来的写法里,外部宏看到内部宏的$(#[$attrs:meta])*,会下意识找自己的重复变量(也就是$variant和$t),但这俩变量根本没在这个重复结构里,所以直接报错。现在我们给它套了一层$()*,相当于告诉外部宏:“这部分是内部宏自己的重复逻辑,你别瞎管,原封不动给我传过去就行”。外部宏一看这结构里没用到自己的重复变量,就会乖乖把它展开成内部宏需要的$(#[$attrs:meta])*,让内部宏自己处理属性的重复逻辑。
另外提个小细节:以后你在嵌套宏里用到其他重复语法(比如重复函数参数),也可以用这个套层技巧避开外部宏的解析干扰。
备注:内容来源于stack exchange,提问作者mwlon
相关产品推荐
相关产品推荐

