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_use]属性。它不仅适用于模组,同样适用于extern crate。例如:

#[macro_use]
mod macros {
    macro_rules! X { () => { Y!(); } }
    macro_rules! Y { () => {} }
}

X!();Run

可通过#[macro_export]将宏从当前crate导出。注意,这种方式无视所有可见性设定。

定义库包macs如下:

mod macros {
    #[macro_export] macro_rules! X { () => { Y!(); } }
    #[macro_export] macro_rules! Y { () => {} }
}

// X!和Y!并非在此处定义的,但它们**的确**被
// 导出了,即便macros并非pub。Run

则下述代码将成立:

X!(); // X!已被定义
#[macro_use] extern crate macs;
X!();Run

注意只有在根模组中,才可将#[macro_use]用于extern crate

最后,在从extern crate导入宏时,可显式控制导入哪些宏。可利用这一特性来限制命名空间污染,或是覆写某些特定的宏。就像这样:

// 只导入`X!`这一个宏
#[macro_use(X)] extern crate macs;

// X!(); // X!已被定义,但Y!未被定义

macro_rules! Y { () => {} }

X!(); // 均已被定义

fn main() {}Run

当导出宏时,常常出现的情况是,宏定义需要其引用所在crate内的非宏符号。由于crate可能被重命名等,我们可以使用一个特殊的替换变量:$crate。它总将被扩展为宏定义所在的crate在当前上下文中的绝对路径(比如 :: macs)。

注意这招并不适用于宏,因为通常名称的决定进程并不适用于宏。也就是说,你没办法采用类似$crate::Y!的代码来引用某个自己crate里的特定宏。结合采用#[macro_use]做到的选择性导入,我们得出:在宏被导入进其它crate时,当前没有办法保证其定义中的其它任一给定宏也一定可用。

推荐的做法是,在引用非宏名称时,总是采用绝对路径。这样可以最大程度上避免冲突,包括跟标准库中名称的冲突。