你有没有想过Rust过程宏是如何工作的?此blog系列中,我们将详细介绍过程宏的一些细节。
本系列文章是在我们团队成员 Vladislav Beskrovny 最近在RustCon上做了一个关于这个话题演讲的基础上,并做了一些轻微的修改和补充。
而在这篇文章中,我们从看看Rust中宏的基础知识开始,然后进入过程宏的具体内容。
宏观下的macro
宏在Rust中随处可见,当然也有一些编程语言根本没有使用宏。让我们先看看什么是宏,以及它们带来了什么优势?宏的作用主要在三个方面:
- 元编程 → 编写宏代码从而生成其他代码
- 允许使用自定义的结构来扩展语言
- 减少模板代码的数量
元编程
我们创建一个 vector 并将三个数字 push 其中:
fn main() {
let mut a = Vec::new();
a.push(1);
a.push(2);
a.push(3);
}
上述代码我们同时可以使用标准库的 vec! 来重写它:
fn main() {
let a = vec![1, 2, 3];
}
vec![1,2,3] 是对 vec! 的调用。这个宏是一个声明宏,其声明如下(简化版本):
macro_rules! vec {
($($x:expr),+) => ({
let mut v = Vec::new();
$( v.push($x); )+
v
});
}
此处 $($x:expr),+ 被称为一个 宏模式。宏调用的主体是 [1,2,3],与当前宏模式匹配:
然后,元变量以如下方式被放入扩展模板中:
请注意,宏扩展代码(上图右)看起来非常像我们用于本例的初始代码。事实上,当扩展代码取代了宏调用时,它将原始代码转变为以下内容:
fn main() {
let a = {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
v
};
}
然后,编译器可以像处理普通代码一样上述代码。
TODO!!!
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。