宏是 Rust 程序员工具箱中强大的一部分,而示例宏是获取这份力量的一条相对简单的途径。我们来写一个吧!
什么是宏?维基百科是这么描述的:
在计算机科学中,宏(“macroinstruction”的缩写,源自希腊语 μακρός,意为“长”)是一条规则或模式,它规定如何按照既定的过程,把某个输入序列(通常是一串字符)映射为替换用的输出序列(通常也是一串字符)。把一处宏的使用实例化(转换)为特定序列的这一映射过程,称为宏展开。
说得真好!不过更具体地说,宏是一种特殊语法,让你可以在编译期生成代码。宏可以用于编译期计算,但更多时候,它们只是抽象代码的另一种方式。例如,你很可能已经用过 println!() 和 vec![]。它们各自都可以接受任意数量的实参,因此没法用普通函数来表达。另一方面,它们总是展开成一定数量的、完全标准的 Rust 代码。如果你感兴趣,可以用 cargo expand 子命令来查看代码中宏展开的结果。
想进一步了解 Rust 中的宏,The Rust Book 中有一章很不错的介绍。
借助 vec![] 宏,你可以就地生成任意长度的 Vec。但 Rust 并没有提供就地生成 HashMap 的方法。请编写一个 hashmap!() 宏来解决这个问题。
例如,你写的库的使用者可能会这样写 hashmap!('a' => 3, 'b' => 11, 'z' => 32)。它应该展开为以下代码:
{
let mut hm = HashMap::new();
hm.insert('a', 3);
hm.insert('b', 11);
hm.insert('z', 32);
hm
}
注意,maplit crate 提供了一个可以完美解决这道练习的宏。请自行实现解答,不要使用这个 crate;在看它的源码之前,请先自己尝试一下。