回调

  1. macro_rules! call_with_larch {
  2. ($callback:ident) => { $callback!(larch) };
  3. }
  4. macro_rules! expand_to_larch {
  5. () => { larch };
  6. }
  7. macro_rules! recognise_tree {
  8. (larch) => { println!("#1, 落叶松。") };
  9. (redwood) => { println!("#2, THE巨红杉。") };
  10. (fir) => { println!("#3, 冷杉。") };
  11. (chestnut) => { println!("#4, 七叶树。") };
  12. (pine) => { println!("#5, 欧洲赤松。") };
  13. ($($other:tt)*) => { println!("不懂,可能是种桦树?") };
  14. }
  15. fn main() {
  16. recognise_tree!(expand_to_larch!());
  17. call_with_larch!(recognise_tree);
  18. }

由于宏展开的机制限制,(在Rust1.2中)不可能做到把一例宏的展开结果作为有效信息提供给另一例宏。这为宏的模组化工作施加了难度。

使用递归并传递回调是条出路。作为演示,上例两处宏调用的展开过程如下:

  1. recognise_tree! { expand_to_larch ! ( ) }
  2. println! { "I don't know; some kind of birch maybe?" }
  3. // ...
  4. call_with_larch! { recognise_tree }
  5. recognise_tree! { larch }
  6. println! { "#1, the Larch." }
  7. // ...

可以使用tt的重复来将任意参数转发给回调:

  1. macro_rules! callback {
  2. ($callback:ident($($args:tt)*)) => {
  3. $callback!($($args)*)
  4. };
  5. }
  6. fn main() {
  7. callback!(callback(println("Yes, this *was* unnecessary.")));
  8. }

如有需要,当然还可以在参数中增加额外的标记。