这是我可以创建的MVP,但它基于一段真实的代码:
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);
}
我把它放在match语句中,因为这是我的实际代码的结构,但我不相信这会有什么不同。我明白在这个例子中,简单地使用内联if语句会更容易,但是如果需要对每个条件和结果进行重复逻辑,我相信这是最有效的方法。
错误如下:
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
不仅unfurl!
与宏不匹配,而且它似乎也没有使用后来定义的furls!
宏。为什么连展开都看不见?如何在这种语法中扩展furl?
1条答案
按热度按时间mnemlml81#
正如@kmdreko所解释的,
tt
匹配一个 token tree -一对{}
、()
或[]
以及里面的任何东西,或者任何其他单个token。这些条件是匹配的,因为它们包含在{}
中;但结果不是,而且它也不是一个单一的标记,所以它会出错。解决这个问题的最简单的方法就是把它也放在括号里。你还需要纠正另外两个错误:在展开其他条件并将最后一个手臂包含在块中时,将逗号放回原处,因为它有两个语句:
第二种最简单的方法是将逗号 * 放在前一个条件 * 之后,而不是 * 放在下一个条件 * 之前。如果只有条件(没有结果),则需要在末尾加上逗号。另外,我们需要做的另一件事是省略结果后面的逗号,即使我们在它后面有条件:
最难的事情是保持语法不变,但我会把它作为一个挑战留给你:)提示:这需要TT munching。