Rust系列:初步⚙所有权⚙结构体和枚举类⚙函数进阶⚙泛型和特征⚙并发和线程通信⚙cargo包管理
Rust中宏的概念与C/C++中相类似,是编译期间执行的一系列指令。但和C语言相比,Rust中的宏,有着更加复杂的替换,下面是一个示例
macro_rules! sqr {
($x:expr) => {$x * $x}
}
fn main() {
println!("{}", sqr!(1 + 1));
}
// 运行结果为4
其中,$x的类型是expr,即表达式。sqr的具体操作,就是把表达式$x替换为$x * $x。
仅从上面的示例来看,宏似乎同函数没什么区别,或许优势仅体现在编译期做替换,从而在编译后可以减少一个函数指针的开销。
所以,接下来,不妨用宏实现一个函数无法实现的功能:输入多个参数。
下面用宏实现一个输入参数可变的函数sum,功能是求和。
macro_rules! sum {
( $( $x:expr ),* ) => {
{
let mut n = 0;
$(n += $x;)*
n
}
};
}
fn main(){
println!("{}", sum!(1,2,3,4));
}
编译运行的结果为10,接下来就细致地探讨一下这个宏的替换规则。
首先,输入是
( $( $x:expr ),* )
这里星号起到一个重复匹配的作用,表示左侧的表达式可以重复匹配多次。而左侧的表达式又被分成两部分,最内层的$紧跟着的x是一个表达式,这个表达式没有任何要求。而这个x与后面的逗号与前面的$符号则形成了外层的匹配模式。
结合我们的输入
sum!(1,2,3,4)
摘掉调用宏时用到的sum!(),其真正被替换的值便是1,2,3,4,而与宏定义中表达式相匹配的,则可理解为依次是
1
,
2
,
3
,
4
从而宏的替换内容,可以被拆解为
let mut n = 0;
n += 1;
n += 2;
n += 3;
n += 4;
return n
于是,求和的功能就通过宏的方式实现了。