如何用宏生成数组!通过对每个元素应用一个函数?

问题描述 投票:0回答:1

我想在宏的帮助下生成一个静态数组(不能在运行时执行此操作)。

我的尝试是

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

rust macros
1个回答
1
投票

您的宏扩展为多个逗号分隔的表达式,这是无效的。它必须只生成一个。

通常的解决方案是下推累积:在宏中累积结果数组并不断向其中添加元素:

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) ),* ]
    };
}
© www.soinside.com 2019 - 2024. All rights reserved.