macros.md
commit: 012bfafbd995c54a86ebb542bbde5874710cba19
本章译文最后维护日期:2020-1-24
可以使用称被为宏的自定义句法形式来扩展 Rust 的功能和句法。宏需要被命名,并通过一致的句法去调用:some_extension!(...)
。
定义新宏有两种方式:
- 声明宏(Macros by Example)以更高级别的声明性的方式定义了一套新句法规则。
- 过程宏(Procedural Macros)可用于实现自定义派生。
句法
MacroInvocation :
SimplePath!
DelimTokenTreeDelimTokenTree :
(
TokenTree*)
|[
TokenTree*]
|{
TokenTree*}
TokenTree :
Token排除 定界符(delimiters) | DelimTokenTreeMacroInvocationSemi :
SimplePath!
(
TokenTree*)
;
| SimplePath!
[
TokenTree*]
;
| SimplePath!
{
TokenTree*}
宏调用是在编译时执行宏,并用执行结果替换该调用。可以在下述情况里调用宏:
当宏调用被用作程序项或语句时,此时它应用的 MacroInvocationSemi 句法规则要求它如果不使用花括号,则在结尾处须添加分号。在宏调用或宏(macro_rules
)定义之前不允许使用可见性限定符。
// 作为表达式使用.
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!();