宏的参数列表可以使用符号“+”表明某个参数至少重复一次,符号“*”表明可以重复0~多次。
下面示例中,使用$(...),+包含起来的表达式可以匹配1~多次,表达式之间使用“,”进行分割。另外需要注意的是在上一个示例中,分号是可选的,不是必须的。
// `find_min!` will calculate the minimum of any number of arguments.
macro_rules! find_min {
// Base case:
($x:expr) => ($x);
// `$x` followed by at least one `$y,`
($x:expr, $($y:expr),+) => (
// Call `find_min!` on the tail `$y`
std::cmp::min($x, find_min!($($y),+))
)
}
fn main() {
println!("{}", find_min!(1));
println!("{}", find_min!(1 + 2, 2));
println!("{}", find_min!(5, 2 * 3, 4));
}
内容解析
这段代码展示了Rust宏如何使用重复模式来处理可变数量的参数,特别是通过+和*操作符来制定参数的重复次数。
重复模式语法
- $(...),+ ——表示可以重复至少一次(1~多次)
- $(...),* ——表示可以重复0次或多次(0~多次)
find_min!宏解析
这个宏用于计算任意数量参数的最小值,展示了递归宏的使用方式:
基本情况(单个参数)
($x:expr) => ($x);
当只有一个参数时,直接返回该参数
这是递归的终止条件
递归情况(多个参数)
($x:expr, $($y:expr),+) => (
std::cmp::min($x, find_min!($($y),+))
)
匹配第一个参数$x和后面的一个或多个参数
使用std::cmp::min比较第一个参数和剩余参数的最小值
对剩余参数递归调用find_min!宏
关键点总结
递归宏:宏可以递归调用自身,类似与递归函数
重复模式:
- $(...),+ ——表示可以重复至少一次(1~多次)
- $(...),* ——表示可以重复0次或多次(0~多次)
灵活的参数处理:红可以处理任意数量的参数
表达式求值:宏参数时表达式,会在适当的时候求值
扩展思考
这种模式不仅适用于数学计算,还可以用于:
- 构建复杂数据结构
- 创建DSL(特定领域语言)
- 生成重复的代码模式
- 实现各种编译时计算
这种宏的强大之处在于它的编译时展开,没有运行时开销,同时提供了极大的灵活性。