Macros 宏输出中的转义逗号

Macros 宏输出中的转义逗号,macros,rust,Macros,Rust,我试图写一个宏,使我能够转换 (a,b,c,d)到(a,a+b,a+b+c,a+b+c+d),等等。以下是我到目前为止得到的: macro_rules! pascal_next { ($x: expr) => ($x); ($x: expr, $y: expr) => ( ($x, $x + $y) ); ($x: expr, $y: expr, $($rest: expr),+) => ( ($x, pascal

我试图写一个宏,使我能够转换
(a,b,c,d)
(a,a+b,a+b+c,a+b+c+d)
,等等。以下是我到目前为止得到的:

macro_rules! pascal_next {
    ($x: expr) => ($x);
    ($x: expr, $y: expr) => (
        ($x, $x + $y)
    );
    ($x: expr, $y: expr, $($rest: expr),+) => (
        ($x, pascal_next!(
                $x + $y, $($rest),+
            )
        )
    );
}
然而,有一个问题是它实际上会输出(a,(a+b,(a+b+c,a+b+c+d))。其来源是第二个匹配规则
($x:expr,$y:expr)=>($x,$x+$y)),生成一个额外的方括号,以便有嵌套的方括号。如果我不在外面放一个括号,我会得到错误:

意外令牌:


因此,是否可以在Rust宏中输出逗号

否;宏的结果必须是完整的语法结构,如表达式或项。绝对不能有像逗号或右大括号这样的随机语法位

在得到完整的最终表达式之前,您可以通过简单地不输出任何内容来解决这个问题。瞧

#![功能(跟踪宏)]
宏规则!帕斯卡{
/*
此宏的输入采用以下形式:
```忽略
(
//电流输出累加器。
($($:tt)*);
//当前的加法前缀。
$prefix:expr;
//其余以逗号结尾的元素。
...
)
```
*/
/*
终止条件:没有剩余的输入。如
例如,转储输出。
*/
(
$out:expr;
$\前缀:expr;
) => {
$out
};
/*
否则,我们还有更多的事情要做!
*/
(
($($:tt)*);
$prefix:expr;
$e:expr,$($rest:tt)*
) => {
帕斯卡(
($($out)*$prefix+$e,);
$prefix+$e;
$($剩余)*
)
};
}
宏规则!帕斯卡{
($($es:expr),+)=>{pascal_impl!(();0;$($es),+,)};
}
跟踪宏!(正确);
fn main(){
println!(“{:?}”,pascal!(1,2,3,4));
}
注意:要在稳定的编译器上使用此选项,您需要删除
#![功能(跟踪宏)]
跟踪宏!(正确)行。其他一切都应该很好

它的作用是递归地咀嚼输入,将部分(可能是语义无效的)输出作为输入传递到下一个递归级别。这让我们建立了一个“开放列表”,这是我们无法做到的

然后,一旦输入用完,我们就把部分输出重新解释为一个完整的表达式,然后。。。完成了

我之所以包含跟踪内容,是为了让您看到它运行时的样子:

pascal! { 1 , 2 , 3 , 4 }
pascal_impl! { (  ) ; 0 ; 1 , 2 , 3 , 4 , }
pascal_impl! { ( 0 + 1 , ) ; 0 + 1 ; 2 , 3 , 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , ) ; 0 + 1 + 2 ; 3 , 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 , ) ; 0 + 1 + 2 + 3 ; 4 , }
pascal_impl! { ( 0 + 1 , 0 + 1 + 2 , 0 + 1 + 2 + 3 , 0 + 1 + 2 + 3 + 4 , ) ; 0 + 1 + 2 + 3 + 4 ; }
输出为:

(1, 3, 6, 10)
需要注意的一点是:大量未注释的整数文本可能会导致编译时间的急剧增加。如果发生这种情况,您可以通过简单地注释所有整数文本(如
1i32
)来解决