「这是我参与11月更文挑战的第 9 天,活动详情查看:2021最后一次更文挑战」
macros 是扩展Rust语法的方法之一。正如 rust book 里面所说,它是 "一种编写代码的方式,可以编写其他代码"。本篇将谈论声明性的宏。声明式宏的例子:vec!/println!/format!
。
但是这篇文章不谈程序性宏,不过你可以在 here 阅读它们。
本篇文章是写给初学者。如果你想涉及更高级的相关知识,可以查看以下文章:
- doc.rust-lang.org/book/ch19-0…
- doc.rust-lang.org/reference/m…
- danielkeep.github.io/tlborm/book…
- 国内版本的宏小册(强烈推荐🐛):http://129.28.186.100/tlborm/
为什么需要宏?
本节没有代码,代码在下一节开始。
声明宏(从现在开始,只是 "宏")不是函数,但没有必要否认这种相似性。像函数一样,我们用它们来执行那些本来需要太多的代码行或古怪的命令(例如:vec!/println!
)。这些是使用宏的其中两个原因,但创建宏的原因又是什么?
当你正在开发一个crate时,想为用户提供某个功能,就像 warp
对 path!
或者你想用一个宏作为模板,这样你就不必像我在这里做的那样,创建几个类似的函数。
还有一种情况是,你需要的东西不能用常规的Rust语法来传递,比如一个带有初始值或结构不同的参数的函数(比如vec!,它允许像vec![2,2,2]或vec![2;3]这样的调用)。
既然如此,我相信最好的方法是学习如何使用它们,然后多尝试几次。当它们可能有用的时候,你会记得这种替代方法,并且可以熟练使用他们。
声明宏
下面开始声明一个宏:
macro_rules! etwas {
() => {}
}
你可以用 etwas!()/etwas![]/etwas!{}
等命令调用这个宏,并没有强制使用其中哪一种。
当我们调用一个宏时,也总是使用其中一个,比如 println!("text")
中的小括号或 vec![]
中的方括号,这只是一种使用惯例(我们应该保持这种惯例)。
但在这个宏中发生了什么?什么都没有。让我们添加一些东西,使之更容易直观地了解其结构。
macro_rules! double {
($value:expr) => { $value * 2 }
}
fn main() {
println!("{}", double!(7));
}
=> 的左边是 matcher ,即定义宏可以接受什么作为输入的规则。右边是 transcriber,即输出处理。
不过这不是很重要,但 matcher 和 transcriber 都可以用
()/[]/{}
来写。