Macros

macros.md
commit: 93f9325701a4c8beba06cb439c1fa88b26893844
本章译文最后维护日期:2022-08-21

可以使用称被为宏的自定义句法形式来扩展 Rust 的功能和句法。宏需要被命名,并通过一致的句法去调用:some_extension!(...)

定义新宏有两种方式:

Macro Invocation

宏调用

句法
MacroInvocation :
   SimplePath ! DelimTokenTree

DelimTokenTree :
      ( TokenTree* )
   | [ TokenTree* ]
   | { TokenTree* }

TokenTree :
   Token排除 定界符(delimiters) | DelimTokenTree

MacroInvocationSemi :
      SimplePath ! ( TokenTree* ) ;
   | SimplePath ! [ TokenTree* ] ;
   | SimplePath ! { TokenTree* }

宏调用是在编译时来扩展宏的,并用扩展结果替换该调用。可以在下述情况里调用宏:

当宏调用被用作程序项或语句时,此时它应用的 MacroInvocationSemi 句法规则要求它如果不使用花括号,则在结尾处须添加分号。在宏调用或宏(macro_rules)定义之前不允许使用可见性限定符

#![allow(unused)]
fn main() {
// 作为表达式使用.
let x = vec![1,2,3];

// 作为语句使用.
println!("Hello!");

// 在模式中使用.
macro_rules! pat {
    ($i:ident) => (Some($i))
}

if let pat!(x) = Some(1) {
    assert_eq!(x, 1);
}

// 在类型中使用.
macro_rules! Tuple {
    { $A:ty, $B:ty } => { ($A, $B) };
}

type N2 = Tuple!(i32, i32);

// 作为程序项使用.
use std::cell::RefCell;
thread_local!(static FOO: RefCell<u32> = RefCell::new(1));

// 作为关联程序项使用.
macro_rules! const_maker {
    ($t:ty, $v:tt) => { const CONST: $t = $v; };
}
trait T {
    const_maker!{i32, 7}
}

// 宏内调用宏
macro_rules! example {
    () => { println!("Macro call in a macro!") };
}
// 外部宏 `example` 展开后, 内部宏 `println` 才会展开.
example!();
}