遞迴
巨集可以呼叫自身,就像函式遞迴一樣:
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.