首页 > 数据库 > 数据库开发技术 > [Rust笔记] 规则宏的“卫生保健”
规则宏mbe即是由macro_rules!宏所定义的宏。它的英文全称是Macro By Example。相比近乎“徒手攀岩”的Cpp模板·元编程,rustc提供了有限的编译时宏代码检查功能(名曰:Mixed Hygiene宏的混合保健)。因为rust宏代码·被展开于·编译过程中的语法分析阶段(请见下图),所以rustc相较于g++/gcc拥有更多可用作“代码静态分析”的信息。

rustc仅只对·宏展开式·内的RuleSyntax RuleMeta-variable / 捕获Capturerustc预置占位符。比如,$crate。Fragment SpecifierTranscriberExpansion
local variablealien variablerustc给·宏规则·内所有元变量限定了一个额外且独立的语法上下文syntax context,进而使“外来”变量与“土著”变量相区分。于是,在同一个宏规则内并存两套语法上下文:
using_a!宏的输出结果是8,而不是5,更不是43。这涉及了以下几个知识点:let a = 22;并不能遮蔽其上一条语句let a = 42;对变量a的赋值结果。因此,最后参与表达式(a + 10) / six求值的变量a的值还是42。six能够参与宏展开式内(a + 10) / six表达式的求值运算。four就不能参与宏展开式内表达式的计算。javascript)的惯例有所不同。$e代换入的表达式a + 10有着更高的执行优先级。具体于上例,a + 10两侧的圆括号。这是因为a + 10整体·作为一个AST表达式结点·被注入宏展开代码,而不是被当作三个没有任何语义与关联的token。后者是Cpp模板元编程的作法,因为Cpp模板是在编译过程中的词法分析阶段被展开。(42 + 10) / 6 = 8,而不是(22 + 10) / 6 = 5,更不是42 + 10 / 6 = 43。将所有分析标入代码,则有
let a = 42;语句。然后,观察程序的编译结果:
rustc的抱怨清晰表达了:“只要语法上下文不一致,即便同名变量let a = 22;就糊在眼前,它也视若无睹”。在宏展开式内,代表同一个变量的多个【识别符】 identifier必须
既要,具备完全一样的“词法”名称, 还要,共处于同一个“语法”上下文中, 而不论这些识别符是源于宏内定义的“土著”,还是经由元变量代换而入的“外来者”。
$e代换入宏展开代码的表达式a + eight + 10包含了在·宏调用语句语法上下文·里绑定的变量eight。rustc并没有报怨“找不到eight的定义”,而是eight的定义let eight = 8;绑定语句。其位于宏定义之后与宏调用之前。
item。因此,一旦某个宏被跨模块(甚至跨包)调用,就会发生rustc编译失败和报怨:“从当前作用域,找不到被引用的项”。如下例

rust保留关键字crate::仅指向·程序执行上下文·所在包的根模块,而不是·宏定义上下文·所在包的根模块。就上例而言,即便在上游crate A的helper!宏定义内使用完全限定路径crate::logger::log2db来引用宏外部函数,下游crate B依旧不可避免地出现B::logger::log2dbB::logger::log2dbcrate::始终都是指向是crate B的根模块,但程序设计意图却是调用A::logger::log2db函数。Mixed Hygiene要求 @开发者,在宏展开式内,始终以元变量$crate::引用当前包。相对于保留关键字crate::,元变量$crate::总是被展开为宏定义端包根模块的引用路径。具体于上例,在helper!宏调用语句被展开之后,$crate::logger::log2db会被替换为A::logger::log2db。于是,下游程序包B就能显示地向上游包A寻找依赖项logger::log2db函数。就宏而言,
crate::总是引用宏调用端包的根模块$crate::总是引用宏定义端包的根模块
crate A应该看起来像这样:#![crate_type = "lib"]
#![crate_name = "A"]
// 导出宏
#[macro_export]
macro_rules! helper {
($text: expr) => ($crate::logger::log2db($text))
}
/// 宏展开式的外部项
pub mod logger {
pub fn log2db(text: String) {
println!("写 {} 进入数据库", text);
}
}
/// 单元测试
mod tests {
#[test]
fn log2db(){
helper!("1122".to_string());
}
}

rust太难学,求与君共同进步。原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。