宏中此变量仍在此深度错误处重复

时间:2019-06-13 05:20:59

标签: rust

我写了一个简单的宏:

macro_rules! my_macro {
    {
        f($x:expr, $y:expr, $z:expr);
        $($c:expr => {
            $($m:expr => {
               $($s:expr => $b:expr),+
            }),+
        }),+
    } => {{
            match ($x, $y, $z) {
                $(
                ($c, $m, $s => $b),
                )+
            }
          }};
}

fn main(){

    let c = 0;
    let m = 0;
    let s = 0; 
    my_macro! {
        f (c, m, s);
        cc => {
            mm => {
                ss => b
            }
        }
    }

}

并得到编译器错误:

error: variable 'm' is still repeating at this depth
  --> project/src/mod.rs
   |
39 |                 ($c, $m, $s => $b),
   |                              ^^^^^^^

我不完全理解为什么会这样。 为什么以及如何修复?

1 个答案:

答案 0 :(得分:0)

在您的宏规则中,

f($x:expr, $y:expr, $z:expr);
$($c:expr => {
    $($m:expr => {
       $($s:expr => $b:expr),+
    }),+
}),+

$x$y$z绑定单个expr。但是,绑定了$c的整个列表。此外,与每个$c关联的是$m的整个列表,因为$m仍在与$(...).+关联的$c块内。对于这些$m中的每一个,都绑定了$s s的整个列表。

现在在您的输出中,

{{
    match ($x, $y, $z) {
        $(
        ($c, $m, $s => $b),
        )+
    }
}};

您只能使用$(...)+打开一层列表。一层之后,$m仍然是表达式列表(“重复”),因此不能直接使用。请记住,$m实际上是列表列表(因为每个$m都有一个$c列表),$s实际上是列表列表的列表。

您要么需要重组规则,以便每个$m仅一个$s和一个$c(都在一个$(...),+中),或者您需要重组输出,以使$m$s被解压缩适当的次数。

尝试第一种方法(输入规则中的单个$(...),+)后,我建议采用$c$m$s模式,而不要使用表达式(如(而不是$c: pat中的$c: expr中)。这样一来,它们就可以在比赛分支的左侧使用。

macro_rules! my_macro {
    {
        f($x:expr, $y:expr, $z:expr);
        $($c:pat => {
            $m:pat => {
               $s:pat => $b:expr
            }
        }),+
    } => {
            match ($x, $y, $z) {
                $(
                    ($c, $m, $s) => $b,
                )+
            }
          };
}

真正的解决方案在很大程度上取决于您要完成的工作。