为何macro_rules中用$path::item访问子项会触发语法错误?
问题原因
虽然宏展开后的代码outer::inner::f()语法合法,但macro_rules的片段解析机制在展开前会进行语法检查:$path:path捕获的是一个完整的路径语法节点,在宏定义中直接写$path::f()时,编译器无法将后续的::f()与前面的$path路径节点正确关联——因为path类型的片段本身已经是一个完整的语法单元,后续的::不符合Rust对路径片段后续语法的预期,因此触发编译错误。
解决方法
以下几种方案可以解决这个问题:
方案1:使用Token Tree(tt)捕获
tt是最通用的片段类型,可以捕获任意令牌序列,不会有路径片段的语法限制:
mod outer { pub mod inner { pub fn f() {} } } macro_rules! call_f { ($($tt:tt)*) => { $($tt)*::f() }; } fn main() { call_f!(outer::inner); }
方案2:通过临时导入避免直接拼接路径
利用use将捕获的路径导入为临时名称,再通过临时名称调用函数:
mod outer { pub mod inner { pub fn f() {} } } macro_rules! call_f { ($path:path) => { { use $path as temp_module; temp_module::f() } }; } fn main() { call_f!(outer::inner); }
方案3:捕获分隔的标识符序列
如果确定传入的是由::分隔的标识符,可以直接捕获标识符序列:
mod outer { pub mod inner { pub fn f() {} } } macro_rules! call_f { ($($ident:ident)::+) => { $($ident)::+::f() }; } fn main() { call_f!(outer::inner); }
内容的提问来源于stack exchange,提问作者BallpointBen
相关产品推荐
相关产品推荐

