之前有基友说写的不够看,所以今天特意加餐说一下宏。之前的案例中有提到过可以使用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语言中的宏,种个草慢慢去研究趴。


wslongchen
67 声望11 粉丝

码农一枚.