遞迴

巨集可以呼叫自身,就像函式遞迴一樣:

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.