2

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

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

?

有没有其他方法可以获得类似的功能,有效地让我“枚举”宏的输入序列?

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

4

2 回答 2

1

因为宏不允许以任何形式存储或操作“变量”,所以这个问题变得非常困难。但是,您可以使用迭代器执行相同效果的操作,方法是创建一个迭代器,以您想要的方式“枚举”输入(std::iter::successors例如,使用 ),然后简单地调用iterator.next().unwrap()in $(some-macro-magic-here)

于 2019-12-25T13:06:08.823 回答
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),*)
    }
  }
}

操场

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

于 2019-12-25T16:39:06.310 回答