A macro matcher is the input pattern in a Rust declarative macro rule. Each rule pairs a matcher with a transcriber: when an invocation’s tokens match the pattern, the transcriber supplies replacement code at the invocation site. Rust tries rules from top to bottom, so matcher design determines both which calls are accepted and which expansion runs. section 2.0 section 2.1.3
Write rules inside `macro_rules! name { ... }` as `(matcher) => (transcriber)`. Matchers and transcribers must be delimited with `()`, `{}`, or `[]`; rules are separated by semicolons, with the final semicolon optional. Parentheses are a practical default when nested code blocks could obscure curly-brace rules. section 2.1.1
Matchers can constrain input at several levels:
- An empty matcher, `()`, accepts an invocation with no input and can expand to `Vec::new()`. section 2.1.3
- Literal tokens, such as `(make an empty vec)`, accept only that exact invocation wording. section 2.1.4
- A metavariable such as `$x:expr` captures one Rust expression for reuse by the transcriber. Fragment specifiers can also match identifiers, literals, types, and other syntax. section 2.1.4
- Repetition, such as `[$($x:expr),+]`, accepts one or more comma-separated expressions and captures each for repeated output. section 2.1.4
Prefer the narrowest fragment that fits. `tt` accepts almost any token tree, which is powerful but can make a matcher overly broad and less predictable. A concrete fragment, such as `ident` or `literal`, lets Rust reject more unsuitable calls; use `tt` only when broader input is necessary and test it carefully. section 2.1.4
A vector matcher set
A `my_vec!` macro can use separate matchers for empty input, a literal phrase, one expression, and a comma-separated expression list. For `my_vec!(1, 2, 3)`, the repeated expression matcher captures the values and the transcriber pushes each into a new vector. The same macro can expand `my_vec![]` to `Vec::new()`. section 2.1 section 2.1.4
Order overlapping matchers from most specific to least specific. A rule matching any literal also matches `0`; if it appears before a special `(Give 0)` rule, the special rule is unreachable. Rust may accept this valid but unintended macro, so test every intended branch rather than relying on static checks. section 2.2.4
Matchers support macros that remove boilerplate, provide default-like or variadic call forms, and define small domain-specific languages. Captured input is passed into the transcriber, allowing a compact invocation syntax to produce ordinary Rust code. section 2.5
Listing 2.1 my_vec, our first declarative macro
macro_rules! my_vec { #1
() => [ #2
Vec::new()
]; #3
(make an empty vec) => ( #4
Vec::new()
); #5
{$x:expr} => {
{
let mut v = Vec::new();
v.push($x);
v
}
}; #6
[$($x:expr),+] => (
{
let mut v = Vec::new();
$(
v.push($x);
)+
v
}
)
}
fn main() {
let empty: Vec<i32> = my_vec![];
println!("{:?}", empty); #7
let also_empty: Vec<i32> = my_vec!(make an empty vec);
println!("{:?}", also_empty);
let three_numbers = my_vec!(1, 2, 3);
println!("{:?}", three_numbers); #8
}
Inspect the complete `my_vec!` listing to compare empty, literal, expression, and repeated-expression matchers alongside their invocations. section 2.1
