简化嵌套循环的Rust宏规则

mat*_*thu 3 macros rust

我有一个简单的宏,有三个非常相似的规则:

macro_rules! c {

($exp:expr, for $i:ident in $iter:expr) => (
    {
        let mut r = vec![];
        for $i in $iter {
            r.push($exp);
        }
        r
    }
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr) => (
    {
        let mut r = vec![];
        for $i2 in $iter2 {
            for $i in $iter {
                r.push($exp);
            }
        }
        r
    }
);

($exp:expr, for $i:ident in $iter:expr, for $i2:ident in $iter2:expr, for $i3:ident in $iter3:expr) => (
    {
        let mut r = vec![];
        for $i in $iter {
            for $i2 in $iter2 {
                for $i3 in $iter3 {
                    r.push($exp);
                }
            }
        }
        r
    }
);

}
Run Code Online (Sandbox Code Playgroud)

每个规则与其他规则的不同之处在于for $i:ident in $iter:exp匹配的模式数量.逻辑同样相同.

有没有办法使用重复模式将这些规则简化为一个$(...)*或者$(...)+仍然能够在宏逻辑中表达嵌套循环?

游乐场链接

Evi*_*Tak 6

您可以使用递归TT(令牌树)咀嚼宏:

macro_rules! c {
    (@loop $v:ident, $exp:expr, for $i:ident in $iter:expr) => (
        for $i in $iter {
            $v.push($exp);
        }
    );

    (@loop $v:ident, $exp:expr, for $i:ident in $iter:expr, $($tail:tt)*) => (
        for $i in $iter {
            c!(@loop $v, $exp, $($tail)*);
        }
    );

    ($exp:expr, $(for $i:ident in $iter:expr),*) => (
        {
            let mut r = vec![];
            c!(@loop r, $exp, $(for $i in $iter),*);
            r
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

@loop有的规则完成所有工作.

TT咀嚼递归宏与递归函数非常相似.在每次调用时,它只处理(咀嚼)输入的一部分,生成中间输出,并将剩余的"未被篡改"的输入尾发送到另一个宏调用.最终,输入足够小,不再需要任何宏调用,并达到递归终止的基本情况.

这里,递归@loop规则捕获与之匹配的单个标记树for $i:ident in $iter:expr,并将剩余的输入(其他此类for $i in $iter表达式)存储在a中$($tail:tt)*.宏规则然后为捕获的for $i in $iter表达式生成循环,并通过使用unmunched input()调用相同的规则来生成循环体$($tail)*.

最终,$($tail)*只包含一个可以匹配的标记树for $i:ident in $iter:expr.在这种情况下,@loop调用基本情况规则,生成最内层的循环,将表达式推送到Vec.

for $i in $iter只要宏保持在宏递归限制内,该宏应该适用于任意数量的表达式.如果您发现自己遇到了递归限制,则可以通过在递归规则中一次处理两个 for $i:ident in $iter:expr表达式来减少递归调用的数量@loop.

铁锈游乐场