Rust宏分支无法匹配unfurl!宏的原因及展开方法问询
Rust宏匹配问题:unfurl!无法识别及展开方案
问题描述
以下是最小可复现代码:
fn testmatch() -> i32 { let dependant = 4; macro_rules! testmacro { () => { return 0 }; ({ $cond:expr => $res:literal } $(, $rest:tt)*) => { if $cond { return $res; } else { return testmacro!($($rest)*); } }; (unfurl!($furled:ident) $(, $rest:tt)*) => { furls!($furled); testmacro!($($rest)*); }; } macro_rules! furls { (test_furl) => { testmacro! { { dependant == 4 => 4 }, { dependant == 5 => 5 } } }; } match 1 { 1 => testmacro! { { dependant == 2 => 2 }, { dependant == 3 => 3 }, unfurl!(test_furl) }, _ => 4000000 } } fn main() { let x = testmatch(); println!("{}", x); }
运行代码时出现以下错误和警告:
error: no rules expected the token `!` --> src/main.rs:32:19 | 4 | macro_rules! testmacro { | ---------------------- when calling this macro ... 32 | unfurl!(test_furl) | ^ no rules expected this token in macro call | = note: while trying to match sequence end warning: unused macro definition: `furls` --> src/main.rs:21:18 | 21 | macro_rules! furls { | ^^^^^ | = note: `#[warn(unused_macros)]` on by default
问题原因
- 宏匹配模式不匹配:
testmacro!的第三个分支模式(unfurl!($furled:ident) $(, $rest:tt)*)期望匹配unfurl!test_furl(无括号)的写法,但实际调用时传入的是unfurl!(test_furl)(带括号)。Rust的macro_rules!按词法token严格匹配,模式中未包含括号,因此无法识别(token,导致匹配失败。 - furls!未被调用:由于
testmacro!的分支未匹配成功,furls!宏从未被执行,因此触发未使用警告。
解决方案
步骤1:修正宏匹配模式
修改testmacro!的第三个分支,让模式包含括号,匹配unfurl!(test_furl)的完整结构:
(unfurl!($furled:ident) $(, $rest:tt)*) => { let res = furls!($furled); if res != 0 { res } else { testmacro!($($rest)*) } };
步骤2:调整宏的返回逻辑
原代码中使用return会直接终止函数,导致后续宏调用被忽略。改为让宏返回表达式,通过条件判断衔接后续逻辑:
macro_rules! testmacro { () => { 0 }; ({ $cond:expr => $res:literal } $(, $rest:tt)*) => { if $cond { $res } else { testmacro!($($rest)*) } }; (unfurl!($furled:ident) $(, $rest:tt)*) => { let res = furls!($furled); if res != 0 { res } else { testmacro!($($rest)*) } }; }
完整修改后的代码
fn testmatch() -> i32 { let dependant = 4; macro_rules! testmacro { () => { 0 }; ({ $cond:expr => $res:literal } $(, $rest:tt)*) => { if $cond { $res } else { testmacro!($($rest)*) } }; (unfurl!($furled:ident) $(, $rest:tt)*) => { let res = furls!($furled); if res != 0 { res } else { testmacro!($($rest)*) } }; } macro_rules! furls { (test_furl) => { testmacro! { { dependant == 4 => 4 }, { dependant == 5 => 5 } } }; } match 1 { 1 => testmacro! { { dependant == 2 => 2 }, { dependant == 3 => 3 }, unfurl!(test_furl) }, _ => 4000000 } } fn main() { let x = testmatch(); println!("{}", x); // 输出4 }
运行结果
修改后的代码会正确展开宏,输出4,且不再有错误和警告。
内容的提问来源于stack exchange,提问作者MaxTretikov
相关产品推荐
相关产品推荐

