我想在宏的帮助下生成一个静态数组(不能在运行时执行此操作)。
我的尝试是
macro_rules! test {
($($data:expr),*) => {
[ test!(@xform $($data),*) ]
};
(@xform) => { };
(@xform $a:expr) => { be32($a) };
(@xform $a:expr, $($data:expr),*) => { be32($a), test!(@xform $($data),*) };
}
// just for simplicity...
const fn be32(v: u32) -> u32 { v + 1 }
static FILE_HEADER_0: [u32;2] = test!(1, 2);
static FILE_HEADER_1: [u32;2] = [be32(1), be32(2)];
但这失败了
error: macro expansion ignores token `,` and any following
--> src/lib.rs:8:52
|
3 | [ test!(@xform $($data),*) ]
| ------------------------- help: you might be missing a semicolon here: `;`
| |
| caused by the macro expansion here
...
8 | (@xform $a:expr, $($data:expr),*) => { be32($a), test!(@xform $($data),*) };
| ^
|
= note: the usage of `test!` is likely invalid in expression context
我希望
FILE_HEADER_0
的生成方式类似于 FILE_HEADER_1
这可以用普通的
macro_rules!
还是我必须使用proc_macro
?
您的宏扩展为多个逗号分隔的表达式,这是无效的。它必须只生成一个。
通常的解决方案是下推累积:在宏中累积结果数组并不断向其中添加元素:
macro_rules! test {
($($data:expr),*) => {
test!(@xform [] $($data),*)
};
(@xform $arr:tt) => { $arr };
(@xform [ $($arr:tt)* ] $a:expr) => {
test!(@xform [ $($arr)* be32($a) ])
};
(@xform [ $($arr:tt)* ] $a:expr, $($data:expr),*) => {
test!(@xform [ $($arr)* be32($a), ] $($data),*)
};
}
在第一个扩展中我们将有
test!(@xform [] 1, 2)
。这将到达最后一个臂并扩展到test!(@xform [ be(1), ] 2)
。这将(通过第三臂)扩展到 test!(@xform [ be(1), be(2) ])
,最终将通过第二臂扩展到 [be(1), be(2)]
。
但是,在这种情况下,您不需要复杂的解决方案。一个简单的宏就可以了:
macro_rules! test {
($($data:expr),*) => {
[ $( be32($data) ),* ]
};
}