macros - 简化嵌套循环的 Rust 宏规则

标签 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
    }
);

}

每条规则与其他规则的区别在于匹配的for $i:ident in $iter:exp 模式的数量。道理也是一样的。

有没有一种方法可以使用 $(...)*$(...)+ 等重复模式将这些规则简化为一个并且仍然是能用宏逻辑表达嵌套循环吗?

Playground link

最佳答案

您可以使用 recursive TT (token tree) munching macro :

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

标有 @loop 的规则做所有的工作。

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

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

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

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

Rust Playground

关于macros - 简化嵌套循环的 Rust 宏规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48856777/

相关文章:

带有表达式不需要的结果的 C 宏

linux - 找不到 AX_CXX_COMPILE_STDCXX_11 宏

rust - 使用线程和async/await时如何解决 "cannot return value referencing local data"?

rust - 如何在没有for循环的情况下获取迭代中正在处理的当前元素的索引?

rust - 了解 Rust 中 "super"关键字的具体用法

http - 如何使用 Reqwest 设置请求 header ?

macros - tt 元变量类型在 Rust 宏中意味着什么?

c - 为什么 'max'宏在C中是这样定义的?

c - 用于简单链表追加的通用 C 宏

class - 来自 Python 的类接口(interface)设计可以在 Rust 中得到反射(reflect)吗?