rust代码编译过程与宏展开过程
rust代码编译过程
声明宏展开
Rust 的声明宏在编译时对代码进行转换,因此其展开过程是在编译期间完成的。展开过程可以分为三个阶段:
- Tokenization:解析输入的 Rust 代码,将其转换成一个个 token(如标识符、关键字、符号等)。
- Parsing:将 token 转化成语法树,用于对代码进行进一步处理。
- Expansion:对语法树进行处理,生成最终的代码。
在第三个阶段,宏会根据语法树中的特定模式对代码进行重构。这些模式可以是任何 Rust 代码片段,包括类型、结构体、函数、表达式等。宏甚至可以递归地展开自己。
展开过程中,宏的实现代码可以使用标准的 Rust 代码编写,包括控制结构和函数调用等。
展开后的代码与宏的实现代码完全一样,因此对于用户而言,使用宏和使用函数没有什么区别。
过程宏展开
属性宏和类型宏展开过程的流程较为相似,都需要解析宏参数、生成新的属性或类型、修改原有属性或类型,并返回属性或类型等步骤。但是由于其作用的范围不同,展开过程中需要解析的内容也不尽相同。例如,类型宏需要解析的是类型参数,用于生成新的类型;而属性宏需要解析的是属性参数,用于生成新的属性。
- 函数宏和其他两种宏不同的是,函数宏需要对整个函数体进行处理,并生成新的代码。在执行完预处理逻辑和解析函数体后,需要判断是否需要进行额外处理,然后才能最终生成新代码并返回。
对比
声明宏
属性宏/类型宏
函数宏
异同点
不能修改源代码
- 作用于某个规模较小的表达式或语句
- 可以在声明中使用
- 作用于某个规模较小的表达式或语句
- 可以在声明中使用
可以修改源代码
- 作用于属性/类型
- 可以在声明中使用
- 作用于属性/类型
- 可以在声明中使用
生成新的代码
- 不能修改原有代码
- 作用于整个函数体
- 不能在声明中使用
- 不能修改原有代码
- 作用于整个函数体
- 不能在声明中使用
使用场景
封装底层功能
- 生成器语法扩展
- DRY原则
- 生成器语法扩展
- DRY原则
重载运算符
- 自定义标记
- 序列化/反序列化
- 自定义标记
- 序列化/反序列化
实现特殊流程控制
- 实现嵌套参数模板
- 实现嵌套参数模板
关键字
macro
- derive
- repr
- allow
- compiler_builtins
- link
- repr
- allow
- compiler_builtins
- link
macro_rules