示例
两种方式实现自定义宏:
通过标准库提供的macro_rules!宏实现
通过提供编译器扩展来实现
编译器扩展只能在不稳定版本中使用。它的API正在重新设计中,还没有正式定稿,这就是所谓的macro 2.0。
实现这样一个宏定义
1 | let counts = hashmap! ['A' => 0, 'C' => 0, 'G' => 0, 'T' => 0]; |
实现了hashmap! {‘A’ => ‘1’}
1 | macro_rules! hashmap { |
我们希望这个宏扩展开后的类型是HashMap,而且进行了合理的初始化,那么我们可以使用“语句块”的方式来实现:
1 | macro_rules! hashmap { |
现在我们希望在宏里面,可以支持重复多个这样的语法元素。我们可以使用+模式和*模式来完成。类似正则表达式的概念,+代表一个或者多个重复,*代表零个或者多个重复。因此,我们需要把需要重复的部分用括号括起来,并加上逗号分隔符:
1 | macro_rules! hashmap { |
最后,我们在语法扩展的部分也使用*符号,将输入部分扩展为多条insert语句。最终的结果如下所示:
1 | macro_rules! hashmap { |
宏1.1
对于一些简单的宏,这种“示例型”(by example)的方式足够使用了。但是更复杂的逻辑则需要通过更复杂的方式来实现,这就是所谓的“过程宏”(procedural macro)。它是直接用Rust语言写出来的,相当于一个编译器插件。但是编译器插件的最大问题是,它依赖于编译器的内部实现方式。一旦编译器内部有所变化,那么对应的宏就有可能出现编译错误,需要修改。因此,Rust中的“宏”一直难以稳定。