我的目标是制作一个能够以描述元组初始化的方式扩展的宏。
我做了这个玩具示例:
macro_rules! fill_tuple {
($_idx : expr) => {};
($idx : expr, $kind : ident) => {
$idx
};
($idx : expr, $head : ident, $($tail : ident),+) => {
fill_tuple!($idx, $head),
fill_tuple!($idx + 1usize, $($tail),+)
};
}
fn main()
{
(
fill_tuple!(0usize, A,B,C)
)
}
这里的思路是,有3个参数,展开后应该得到(0, 1, 2)。这只是一个示例,最后我将以更复杂的方式实际使用 A、B、C 来初始化元组。
我目前的障碍是宏最后一 block 的逗号不被 rust 接受。我收到错误:
Compiling playground v0.0.1 (/playground)
error: macro expansion ignores token `,` and any following
--> src/main.rs:7:33
|
7 | fill_tuple!($idx, $head),
| ^
...
15 | fill_tuple!(0usize, A,B,C)
| --------------------------- help: you might be missing a semicolon here: `;`
| |
| caused by the macro expansion here
|
= note: the usage of `fill_tuple!` is likely invalid in expression context
我该如何解决这个问题?我绝对需要那个逗号,否则整个生成的代码都是错误的。
最佳答案
您可以递归地遍历宏参数并保留结果数字的列表。
macro_rules! fill_tuple {
// Base cases
(@step 0, (),) => {
()
};
(@step $i:expr, ($($result:expr),*), $head:expr) => {
($($result,)* foo($i, $head),)
};
// Recursive case
(@step $i:expr, ($($result:expr),*), $head:expr, $($tail:expr),+) => {
fill_tuple!(@step $i + 1, ($($result,)* foo($i, $head)), $($tail),+)
};
// Public interface
($($e:expr),*) => {
fill_tuple!(@step 0, (), $($e),*)
};
}
如果不需要索引,那就简单多了:
macro_rules! fill_tuple {
($($e:expr),*) => {
($(bar($e),)*)
}
}
关于单元素元组有一些微妙的细节,因为您必须将值放在括号中并在值后紧跟一个逗号——例如,(7,)
而不是 (7)
。所以在第一个宏中,我们需要在 ($($result,)* foo($i, $head),)
行的 foo()
之后加上逗号。同样,在第二个宏中,我们需要 ($(bar($e),)*)
而不是 ($(bar($e)),*)
以便每个值后面都有一个逗号,而不是每个值(最后一个除外)。
关于rust - 将宏扩展为元组初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73677012/