Week 15 - Declarative Macros (macro_rules!)¶
15.1 Conceptual Core¶
macro_rules!is a pattern-matching macro system operating on token trees. It is hygienic by default-identifiers introduced in the macro do not collide with identifiers in the call site (with subtle exceptions you must learn).- Designators:
expr,ident,ty,pat,tt,block,stmt,path,meta,vis,lifetime,literal,item. Each constrains what tokens the matcher accepts and how they may be re-emitted. - Repetition:
$( ... )*,$( ... )+,$( ... ),*. The macro author is responsible for handling empty/non-empty cases.
15.2 Mechanical Detail¶
- Hygiene exceptions:
$crateis the canonical way to refer to the defining crate. Without it,vec![1,2,3]would break if the user shadowedstd::vec. Use$crate::in every path emitted by a macro. - Recursion: macros may invoke themselves. The recursion limit is
#![recursion_limit = "256"]by default-raise it explicitly if needed (and document why). - TT munching: a pattern where the macro consumes tokens one at a time recursively. The standard idiom for parsing custom DSLs in
macro_rules!. - Re-export discipline:
#[macro_export]makes a macro visible at the crate root. The 2018+ edition allowspub useof macros, which is the modern preferred path.
15.3 Lab-"A hashmap! Macro With Diagnostics"¶
Implement a hashmap! macro:
- hashmap! { "a" => 1, "b" => 2 } produces a HashMap.
- Trailing comma allowed.
- Type-checks: a typo like hashmap! { "a" => 1, "b" -> 2 } should produce a useful error pointing at the bad token (use compile_error! strategically).
- Pre-allocates with HashMap::with_capacity.
15.4 Idiomatic & Clippy Drill¶
clippy::crate_in_macro_def(use$crate::),clippy::single_call_fn,clippy::useless_format. Read the Little Book of Rust Macros sections on hygiene and TT munching.
15.5 Production Hardening Slice¶
- Add
cargo-expandto your dev tooling. Inspect the expansion of every macro you ship; commit a sample expansion as a doctest. This is your guard against silent semantic drift in macro maintenance.