【发布时间】:2019-06-30 08:38:48
【问题描述】:
我有一个标识符列表,我想为该列表中的每对标识符调用一个宏。例如,如果我有a、b 和c,我想生成这个:
println!("{} <-> {}", a, a);
println!("{} <-> {}", a, b);
println!("{} <-> {}", a, c);
println!("{} <-> {}", b, a);
println!("{} <-> {}", b, b);
println!("{} <-> {}", b, c);
println!("{} <-> {}", c, a);
println!("{} <-> {}", c, b);
println!("{} <-> {}", c, c);
当然,这是一个虚拟的例子。在我的真实代码中,标识符是类型,我想生成 impl 块或类似的东西。
我的目标是只列出每个标识符一次。在我的真实代码中,我有大约 12 个标识符并且不想手动写下所有 12² = 144 对。所以我认为宏可能会帮助我。我知道可以使用所有强大的过程宏来解决它,但我希望它也可以使用声明性宏 (macro_rules!)。
我尝试了我认为是处理这个问题的直观方法(两个嵌套的“循环”)(Playground):
macro_rules! print_all_pairs {
($($x:ident)*) => {
$(
$(
println!("{} <-> {}", $x, $x); // `$x, $x` feels awkward...
)*
)*
}
}
let a = 'a';
let b = 'b';
let c = 'c';
print_all_pairs!(a b c);
但是,这会导致此错误:
error: attempted to repeat an expression containing no syntax variables matched as repeating at this depth
--> src/main.rs:4:14
|
4 | $(
| ______________^
5 | | println!("{} <-> {}", $x, $x);
6 | | )*
| |_____________^
我想这有点道理,所以我尝试了其他方法 (Playground):
macro_rules! print_all_pairs {
($($x:ident)*) => {
print_all_pairs!(@inner $($x)*; $($x)*);
};
(@inner $($x:ident)*; $($y:ident)*) => {
$(
$(
println!("{} <-> {}", $x, $y);
)*
)*
};
}
但这会导致与上面相同的错误!
声明性宏是否可以做到这一点?
【问题讨论】:
-
声明性宏的表达能力肯定是有缺陷的。但是我在 proc 宏中遇到了与
quote相同的问题。当您有两个重复变量时,它们总是成对插值,并且对所有排列进行插值非常棘手。
标签: rust rust-macros rust-decl-macros