卫生性

卫生性 (hygiene) 是宏的一个重要概念。它描述了宏在其语法上下文中工作的能力:不影响或不受其周围环境的影响。

换句话说,这意味着语法扩展应该可以在任何地方调用,而不会干扰其周围的上下文。

在一个完美的世界里,Rust 中的所有语法扩展都是完全卫生的 (fully hygienic),不幸的是情况并非如此,所以应该注意避免编写不是完全卫生的语法扩展。

我们将在这里深入讨论一般的卫生性概念,这些概念会在 Rust 提供的不同语法扩展的相应的卫生性章节中涉及到。

卫生性主要影响从语法扩展产生的标识符和路径。

简而言之,如果由语法扩展创建的标识符不能被调用该语法扩展的环境访问,那么它对于该标识符是卫生的。

同样,如果语法扩展中使用的标识符不能引用到在语法扩展之外定义的内容,则被认为是卫生的。

注意:这里说的“创建”和“使用”是指该标识所在的位置。

之所以说 struct Foo{} 中的 Foolet foo = …; 中的 foo 是被创建的,是因为在某种角度看,它们在其名字下引入了新的东西。

而之所以说 fn foo(_:foo){} 中的 foofoo + 3 中的 foo 是被使用的,是因为从某种角度看,它们正指向某些已存在的东西。

最好的例子用例子来展示。假设某语法扩展 make_local 展开为 let local = 0;,也就是说,它创建了标识符 local,然后假设有以下代码:

macro_rules! make_local {
    () => { let local = 0; }
}
fn main() {
    make_local!();
    assert_eq!(local, 0);
}

如果 assert_eq!(local, 0); 中的 local 被解析为语法扩展所定义的 local,则语法扩展不是卫生的(至少在 local 这个名称/绑定方面不是卫生的)。

现在假设有某语法扩展 use_local 展开为 local = 42;,也就是说,它使用了标识符 local,然后假设有以下代码:

// 注释这段声明宏的定义看看会发生什么
macro_rules! use_local {
    () => { local = 42; }
}
fn main() {
    let mut local = 0;
    // 取消注释这段声明宏的定义看看会发生什么
    // macro_rules! use_local {
    //     () => { local = 42; }
    // }
    use_local!();
}

如果给定调用的语法扩展中的 local 被解析为调用前所定义的 local ,则该语法扩展也不是卫生的。

这简短地介绍了卫生性的一般概念。它将在相应的 macro_rules!proc-macro 章节里进行更深入的解释,并阐述其各自的特有之处。