1. 1. Introduction
  2. 2. 宏,彻底剖析
    1. 2.1. 语法扩展
      1. 2.1.1. 源码解析过程
      2. 2.1.2. AST中的宏
      3. 2.1.3. 展开
    2. 2.2. macro_rules!
    3. 2.3. 细枝末节
      1. 2.3.1. 再探捕获与展开
      2. 2.3.2. 卫生性
      3. 2.3.3. 不是标识符的标识符
      4. 2.3.4. 调试
      5. 2.3.5. 作用域
      6. 2.3.6. 导入/导出
  3. 3. 宏,实践介绍
  4. 4. 常用模式
    1. 4.1. 回调
    2. 4.2. 标记树撕咬机
    3. 4.3. 内用规则
    4. 4.4. 下推累积
    5. 4.5. 重复替代
    6. 4.6. 尾部分隔符
    7. 4.7. 标记树聚束
    8. 4.8. 可见性
    9. 4.9. 临时措施
  5. 5. 轮子
    1. 5.1. AST强转
    2. 5.2. 计数
    3. 5.3. 枚举解析
  6. 6. 实例注解
    1. 6.1. Ook!

标记树撕咬机

macro_rules! mixed_rules {
    () => {};
    (trace $name:ident; $($tail:tt)*) => {
        {
            println!(concat!(stringify!($name), " = {:?}"), $name);
            mixed_rules!($($tail)*);
        }
    };
    (trace $name:ident = $init:expr; $($tail:tt)*) => {
        {
            let $name = $init;
            println!(concat!(stringify!($name), " = {:?}"), $name);
            mixed_rules!($($tail)*);
        }
    };
}Run

此模式可能是最强大的宏解析技巧。通过使用它,一些极其复杂的语法都能得到解析。

“标记树撕咬机”是一种递归宏,其工作机制有赖于对输入的顺次、逐步处理。处理过程的每一步中,它都将匹配并移除(“撕咬”掉)输入头部的一列标记,得到一些中间结果,然后再递归地处理输入剩下的尾部。

名称中含有“标记树”,是因为输入中尚未被处理的部分总是被捕获在$($tail:tt)*的形式中。之所以如此,是因为只有通过使用tt的重复才能做到无损地捕获住提供给宏的部分输入。

标记树撕咬机仅有的限制,也是整个宏系统的局限:

然而,需要把宏递归的局限性纳入考量。macro_rules!没有做任何形式的尾递归消除或优化。在写标记树撕咬机时,推荐多花些功夫,尽可能地限制递归调用的次数。对于输入的变化,增加额外的匹配分支(而非采用中间层并使用递归);或对输入句法施加限制,以便于对标准重复的记录追踪。