我可以“枚举” Rust的可变参数宏吗?

时间:2019-12-25 05:26:46

标签: rust rust-macros

基本上,我有一个看起来像这样的宏:

macro_rules! my_macro {
  ( $expr:expr; $( $pat:pat ),* ) => {
    match $expr {
      $(
        $pat => $(some-macro-magic-here),
      )*
    }
  }
}

是否有可以放入$(some-macro-magic-here)的内容,所以

my_macro!(foo; A, B, C)

将扩展为

match foo {
  A => 2,
  B => 4,
  C => 6,
}

还有其他方法可以使我有效地让我“枚举”宏的输入顺序吗?

我想我可能可以写一个递归宏来获得类似的效果,但是我想知道是否有比我所想的更优雅/惯用的方式

2 个答案:

答案 0 :(得分:1)

因为不允许宏以任何形式存储或操作“变量”,所以这个问题变得非常困难。但是,您可以使用迭代器来实现相同的效果,方法是创建一个迭代器,以所需的方式“枚举”输入(例如,使用std::iter::successors),然后简单地调用{{1 }}在iterator.next().unwrap()中。

答案 1 :(得分:1)

您无法创建这样的match语句,因为Rust不允许通过宏创建match分支,因此这暂时不起作用:

match val {
    my_macro! (A, B, C)
}

但是,在这种情况下,我们可以使用嵌套的if let块并使用递归宏来“破解”:

macro_rules! my_macro {
  ($expr:expr; $($pat:pat),*) => {
    my_macro!($expr; 2, 2; $($pat),*)
  };
  ($expr:expr; $curr:expr, $step:literal; $pat:pat) => {
    if let $pat = $expr {
        $curr
    } else {
        unreachable!()
    }
  };
  ($expr:expr; $curr:expr, $step:literal; $pat:pat, $($rest:pat),*) => {
    if let $pat = $expr {
        $curr
    } else {
        my_macro! ($expr; $curr+$step, $step; $($rest),*)
    }
  }
}

Playground

它将生成嵌套条目,并添加足够的2以创建预期的常量。或者,您可以将其替换为乘法,但是无论如何应该由编译器对其进行优化。