【问题标题】:Side by side macro repetition with same separator具有相同分隔符的并排宏重复
【发布时间】:2021-03-02 01:30:14
【问题描述】:

真的不能创建这样的宏还是我做错了:

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");

我试过的是这个(playground link):

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

【问题讨论】:

    标签: rust macros


    【解决方案1】:

    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 而不是$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");
    }
    

    另见:

    【讨论】:

      【解决方案2】:

      你做的几乎是正确的——尾随的逗号会使编译器出错。 Removing the comma works just fine. 如果您想知道为什么,那是因为 macro_rules 调用非常挑剔。当它读取尾随逗号时,它会查看下一个标记,即a,但由于这不是文字,所以它没有做更明智的事情,即检查下一个模式,它就放弃了。

      【讨论】:

        猜你喜欢
        • 2023-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-25
        • 2021-11-10
        • 2021-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多