我的目标是制作一个能够以一种我可以描述元组初始化的方式展开的宏.

我做了这个玩具的例子:

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)
    )
}

这里的 idea 是,有3个参数,所以展开后应该得到(0,1,2).这只是一个例子,在最后,我将以一种更复杂的方式使用A、B、C来初始化元组.

我目前的障碍是宏最后一块上的逗号不被Ruust接受.我得到的错误是:

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相关问答推荐

如何在Rust中为具有多个数据持有者的enum变体编写文档 comments ?

阻止websocket中断的中断中断的终端(操作系统错误4)

如何访问Rust存储值的内存地址

如何从铁 rust 中呼唤_mm_256_mul_ph?

rust 蚀生命周期 行为

有没有可能让泛型Rust T总是堆分配的?

将serde_json读入`VEC<;T&>;`( rust 色)时出现问题

允许 rust 迹 struct 条目具有多种类型

解析程序无法在Cargo 发布中 Select 依赖版本

在运行特定测试时,如何 suppress cargo test 的空输出?

期望一个具有固定大小 x 元素的数组,找到一个具有 y 元素的数组

当我编译 Rust 代码时,我是否缺少 AVX512 的目标功能?

如何返回 struct 体中向量的切片

Rust 中的复合 `HashSet` 操作或如何在 Rust 中获得 `HashSet` 的显式差异/并集

在没有任何同步的情况下以非原子方式更新由宽松原子操作 Select 的值是否安全?

Rust并发读写引起的死锁问题

Rust编译器通过哪些规则来确保锁被释放?

更好的方法来模式匹配带有 Rust 的窥视孔装配说明窗口?

如何创建动态创建值并向它们返回borrow 的工厂?

在 Rust 中有条件地导入?