% TT バンドル化
macro_rules! call_a_or_b_on_tail { ((a: $a:expr, b: $b:expr), call a: $($tail:tt)*) => { $a(stringify!($($tail)*)) }; ((a: $a:expr, b: $b:expr), call b: $($tail:tt)*) => { $b(stringify!($($tail)*)) }; ($ab:tt, $_skip:tt $($tail:tt)*) => { call_a_or_b_on_tail!($ab, $($tail)*) }; } fn compute_len(s: &str) -> Option<usize> { Some(s.len()) } fn show_tail(s: &str) -> Option<usize> { println!("tail: {:?}", s); None } fn main() { assert_eq!( call_a_or_b_on_tail!( (a: compute_len, b: show_tail), the recursive part that skips over all these tokens doesn't much care whether we will call a or call b: only the terminal rules care. ), None ); assert_eq!( call_a_or_b_on_tail!( (a: compute_len, b: show_tail), and now, to justify the existence of two paths we will also call a: its input should somehow be self-referential, so let's make it return some ninety one! ), Some(91) ); }
特に複雑な再帰マクロでは、識別子や式を後続の層へ運ぶために、多数の引数が必要になる場合があります。 しかし、実装によっては、これらの引数を転送する必要はあるものの、それらを使用する必要はない中間層が多数存在することがあります。
そのため、そのような引数をすべてグループに入れて単一の TT にまとめると、非常に有用な場合があります。 これにより、引数を使用する必要のない層は、引数グループ全体を正確にキャプチャして置換する代わりに、単一の tt をキャプチャして置換するだけで済みます。
上の例では、$a 式と $b 式をグループにまとめています。そのグループは、再帰ルールによって単一の tt として転送できます。 その後、このグループは終端ルールによって分解され、式にアクセスされます。