卫生性
Rust宏是部分卫生的。具体来说,对于绝大多数标识符,它是卫生的;但对泛型参数和生命周期来算,它不是。
之所以能做到“卫生”,在于每个标识符都被赋予了一个看不见的“句法上下文”。在比较两个标识符时,只有在标识符的明面名字和句法上下文都一致的情况下,两个标识符才能被视作等同。
为阐释这一点,考虑下述代码:
- macro_rules! using_a {
- ($e:expr) => {
- {
- let a = 42;
- $e
- }
- }
- }
- let four = using_a!(a / 10);
我们将采用背景色来表示句法上下文。现在,将上述宏调用展开如下:
- let four = {
- let a = 42;
- a / 10
- };
首先记起,macro_rules!
的调用在展开过程中等同于消失。
其次,如果我们现在就尝试编译上述代码,编译器将报如下错误:
<anon>:11:21: 11:22 error: unresolved name `a`
<anon>:11 let four = using_a!(a / 10);
注意到宏在展开后背景色(即其句法上下文)发生了改变。每处宏展开均赋予其内容一个新的、独一无二的上下文。故而,在展开后的代码中实际上存在两个不同的a
,分别有不同的句法上下文。即,a
与a
并不相同,即它们便看起来很像。
尽管如此,被替换进宏展开中的标记仍然保持着它们原有的句法上下文(因它们是被提供给这宏的,并非这宏本身的一部分)。因此,我们作出如下修改:
- macro_rules! using_a {
- ($a:ident, $e:expr) => {
- {
- let $a = 42;
- $e
- }
- }
- }
- let four = using_a!(a, a / 10);
此宏在展开后将变成:
- let four = {
- let a = 42;
- a / 10
- };
因为只用了一种a
,编译器将欣然接受此段代码。
当前内容版权归 DaseinPhaos 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 DaseinPhaos .