很多编程语言里都没有宏,不过C语言里面是有宏,比如:

    1. #define CALC_SUN(x) 5 * x + x*x + abs(x)

    这样在程序里面我们就可以写:

    1. CALC_SUN2

    然后在编译的时候,系统就会自动展开为 5 _2 + 2 2_ + abs(2). 相比函数而言,这个少了一次调用。不用跳转也不用return。增加了编译的成本,但是提升了运行的性能。
    不过C的宏功能很弱,如果你把 2 写成 1+1, 那么因为*号优先级大于+号,会得出一个错误结果。
    Rust的宏不但没有这个问题,并且应用也十分广泛,别的不说, 就是最简单的hello world都会用到宏:

    1. fn main() {
    2. println!("hello world!");
    3. }

    这里需要注意的是println!println,多了感叹号!,后缀不带感叹号为普通函数,带感叹号的为宏函数,rust不存在println普通函数。看rust的源代码,基本上都是宏,各种感叹号层出不穷。就连定义宏的的方法也是用一个宏去定义!

    1. macro_rules! mymacro {
    2. () =>{}
    3. }

    上面这个就定义了一个什么都不做的宏。不过基本的结构还是在的。宏的结构由 一系列的() =>{} 构成,前面的小括号里面的叫做pattern,一旦传入的参数和这个pattern match成功了,就展开成后面大括号里面的效果。
    别的不说,就连最基本的数据结构,数组向量在rust里面都是一个宏,vec![1, 2,3], 其背后的逻辑是:

    1. macro_rules! vec {
    2. ( $( $x:expr ),* ) => {
    3. {
    4. let mut temp_vec = Vec::new();
    5. $(
    6. temp_vec.push($x);
    7. )*
    8. temp_vec
    9. }
    10. };
    11. }

    $x 是个代数,冒号后面跟的是类型,也就是expression,因为1,2,3, 2+3, 这种都是expression。
    所以$x:expr 的意思就是一个expression,用$x表示。星号 和regular expression 一样,表示0个或者多个的重复,所以$($x:expr), 就是($x:expr) 重复0次或者多次。
    一旦这个模式得到了匹配,就执行后面的内容, let mut temp_vec = Vec::new() 是建立一个temp_vec的空向量,然后下面的$(temp_vec.push($x);)* 表示展开的时候把 temp_vec.push($x) 重复相应的次数。最后一个temp_vec 则是返回值,前面隐藏了一个return。