之前有基友说写的不够看,所以今天特意加餐说一下宏。之前的案例中有提到过可以使用println!
宏进行打印。今天我们就简单来说说有关宏的几个方面:
- 宏与函数的区别
- 如何定义声明式宏(元编程)
宏与函数的区别
宏其实就是我们通常所谓的元编程,在rust中使用宏来扩展生成比我们手写更多的代码。
大家应该知道元编程对于减少大量编写和维护的代码试非常有用的,但他又和函数有点区别,比如一个函数必须要声明它的参数个数和类型。但是宏只接受一个可变参数,而且可以在编译器翻译代码之前展开。这样就意味着我们想要实现一个宏比定义函数更加复杂,也更难理解和维护。
同时在rust中宏定义无法出现在模块命名空间,而且必须要在调用之前定义或者将其导入,而函数则可以在任意地方。
声明式宏
我们可以使用macro_rules!
来定义宏,这在Rust中使用的比较广泛。接下来我们介绍一下vector,这是rust中的一种集合类型。和数组不一样的是他存储在堆上,而且长度是动态增长的。而且vector是std中用泛型实现的,数组是原生内建的类型。具体有关vector的我们暂时不展开,我们只需要了解到可以使用vec!
来生成一个给定值的vector。如:
let v: Vec<i32> = vec![1, 2, 3];
然后我们移步vec!
的实现,这是简化过的定义:
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
首先我们看到的是一个注解,这个说明了该宏是可用的。然后macro_rules!
定义了名字vec后面跟上大括号。然后就是( $( $x:expr ),* )
,这句也就是一个模式(pattern),如果模式匹配了后面的相关代码就会执行。这和后面要说的match表达式的结构类似。然后,一对括号包含了全部模式。接下来是后跟一对括号的美元符号( $ ),其通过替代代码捕获了符合括号内模式的值。$() 内则是 $x:expr ,其匹配 Rust 的任意表达式或给定 $x 名字的表达式。
$() 之后的逗号说明一个逗号分隔符可以有选择的出现代码之后,这段代码与在 $() 中所捕获的代码相匹配。紧随逗号之后的 说明该模式匹配零个或多个 之前的任何模式。
所以当 vec![1, 2, 3]; 调用宏时,$x 模式与三个表达式 1、2 和 3 进行了三次匹配。
就此打住,不然再讲下去打字员也是一脸懵逼了。
自定义过程式宏
在rust中第二种形式的宏叫做过程式宏。接收rust代码作为输入,然后在代码上进行操作产生另外一些代码输出。由于篇幅较长而且打字员也需要补补课所以我们下次再介绍。
小结
看到这里,大家是不是回忆起了C语言中的宏,种个草慢慢去研究趴。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。