首页 > 解决方案 > 具有相同分隔符的并排宏重复

问题描述

实际上不可能创建这样的宏还是我做错了:

sample!("hello", "there") => 

println!("{:?}", "hello");
println!("{:?}", "there");

sample!("hello", "there", a "second type", a "another second type") => 

println!("{:?}", "hello");
println!("{:?}", "there");
println!("second {:?}", "second type");
println!("second {:?}", "another second type");

我试过的是这个(操场链接):

macro_rules! sample {
  ( 
    $( $first:literal ),*
    $( a $second:literal ),*
  ) => {
      $(
        println!("{:?}", $first);
      )*
      $(
        println!("second {:?}", $second);
      )*
  };
}

失败了:

error: no rules expected the token `a`
  --> main.rs:18:20
   |
1  | macro_rules! sample {
   | ------------------- when calling this macro
...
18 |   sample!("hello", a "testing");
   |                    ^ no rules expected this token in macro call

error: aborting due to previous error

标签: rustmacros

解决方案


Rust 宏对分隔符非常严格。

macro_rules! sample {
  ( 
    $( $first:literal, )*
    $( a $second:literal ),*
  ) => {
      $(println!("{:?}", $first);)*
      $(println!("second {:?}", $second);)*
  };
}

fn main() {
  sample!("hello", a "testing");
}

这个样本有效,你能发现变化吗?我将逗号从第一个外部$( ... )移到内部。区别在于:

  • $( $a:literal ),*仅接受"a", "b", "c" (不允许尾随逗号)
  • $( $a:literal, )*仅接受"a", "b", "c", (需要尾随逗号)

在您的宏中,中间逗号不匹配作为第一次或第二次重复的一部分。该错误基本上是说它期望另一个$first而不是a $second,因为这就是重复所说的。

您可以通过引入可选逗号来修复它:

macro_rules! sample {
  ( 
    $( $first:literal ),*
    $(,)? // <----------------
    $( a $second:literal ),*
  ) => {
      $(println!("{:?}", $first);)*
      $(println!("second {:?}", $second);)*
  };
}

这更宽松,但会允许像这样的奇怪事情,这可能会也可能不会,这取决于你想要什么。

sample!("hello", "there",);
sample!(, a "testing");
sample!("hello" a "testing");

不幸的是,如果不使用不同的手臂,我不知道一个完美的解决方案:

macro_rules! sample {
  ($( $first:literal ),*) => { };
  ($( $first:literal, )* $( a $second:literal ),+) => { };
  ($( a $second:literal ),*) => { };
}

fn main() {
  sample!("hello", "there");
  sample!("hello", "there", a "testing");
  sample!(a "second type", a "another second type");
  // sample!("hello", "there",);
  // sample!(, a "testing");
  // sample!("hello" a "testing");
}

也可以看看:


推荐阅读