递归
宏可以调用自身,就像函数递归一样:
macro_rules! sum {
($base:expr) => { $base };
($a:expr, $($rest:expr),+) => { $a + sum!($($rest),+) };
}
让我们来看看 sum!(1, 2, 3)
的扩展:
sum!(1, 2, 3)
// ^ ^~~~
// $a $rest
=> 1 + sum!(2, 3)
// ^ ^
// $a $rest
=> 1 + (2 + sum!(3))
// ^
// $base
=> 1 + (2 + (3))
递归限制
当编译器过于扩展宏时,它会放弃。默认情况下,编译器在将宏扩展到 64 级深度后会失败,因此例如以下扩展将导致失败:
sum!(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62)
// error: recursion limit reached while expanding the macro `sum`
// --> <anon>:3:46
// 3 |> ($a:expr, $($rest:expr),+) => { $a + sum!($($rest),+) };
// |> ^^^^^^^^^^^^^^^^
当达到递归限制时,你应该考虑重构你的宏,例如
- 也许递归可以被重复取代?
- 也许输入格式可以改为不那么花哨的东西,所以我们不需要递归来匹配它?
如果有任何合理的原因,64 级是不够的,你总是可以增加使用属性调用宏的包的限制:
#![recursion_limit="128"]
// ^~~ set the recursion limit to 128 levels deep.