「初看声明宏」介绍

205 阅读2分钟

「这是我参与11月更文挑战的第 9 天,活动详情查看:2021最后一次更文挑战


macros 是扩展Rust语法的方法之一。正如 rust book 里面所说,它是 "一种编写代码的方式,可以编写其他代码"。本篇将谈论声明性的宏。声明式宏的例子:vec!/println!/format!

但是这篇文章不谈程序性宏,不过你可以在 here 阅读它们。

本篇文章是写给初学者。如果你想涉及更高级的相关知识,可以查看以下文章:

为什么需要宏?

本节没有代码,代码在下一节开始。

声明宏(从现在开始,只是 "宏")不是函数,但没有必要否认这种相似性。像函数一样,我们用它们来执行那些本来需要太多的代码行或古怪的命令(例如:vec!/println! )。这些是使用宏的其中两个原因,但创建宏的原因又是什么?

当你正在开发一个crate时,想为用户提供某个功能,就像 warppath! 或者你想用一个宏作为模板,这样你就不必像我在这里做的那样,创建几个类似的函数。

还有一种情况是,你需要的东西不能用常规的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,即输出处理。

不过这不是很重要,但 matchertranscriber 都可以用 ()/[]/{} 来写。