macro_rules!
macro_rules! defines declarative macros by pattern-matching token trees and expanding to Rust code. They are the first tool for lightweight DSLs and repetitive boilerplate.
Search across all documentation pages
macro_rules! defines declarative macros by pattern-matching token trees and expanding to Rust code. They are the first tool for lightweight DSLs and repetitive boilerplate.
macro_rules! hashmap {
($($k:expr => $v:expr),* $(,)?) => {{
let mut m = std::collections::HashMap::new();
$( m.insert($k, $v); )*
m
}};
}When to reach for this: Repetitive syntax that functions cannot abstract (token-level patterns).
macro_rules! assert_returned {
($expr:expr, $pat:pat) => {
match $expr {
$pat => {}
other => panic!("unexpected: {:?}", other),
}
};
}
#[test]
fn parses() {
assert_returned!(parse("42"), Ok(42));
}What this demonstrates:
$(,)? optional trailing comma#[macro_export] for crate root visibilitymacro_rules! op {
(add $a:expr, $b:expr) => { $a + $b };
(mul $a:expr, $b:expr) => { $a * $b };
}macro_rules! count {
() => { 0 };
($head:tt $(, $tail:tt)*) => { 1 + count!($($tail),*) };
}compile_error! with clear text for invalid input.cargo expand.#[macro_export] or pub use. Fix: document macro path my_crate::hashmap!.| Alternative | Use When | Don't Use When |
|---|---|---|
const fn / generics | Compile-time logic expressible as fn | Need custom syntax |
| Proc macro | Complex AST transforms | Simple token templates |
build.rs codegen | Large generated modules | Small call-site sugar |
macro_rules for pattern templates; proc for full AST (derive, attributes).
#[macro_export] puts at crate root; re-export with pub use crate::macro_name;.
Expand to async block inside fn; macro itself not async.
Token tree - captures arbitrary token subtree for flexible matchers.
Use $( $e:expr );* with semicolon separation.
/// on macro_rules! block documents in rustdoc.
Same macro_rules model; follow edition for generated code use paths.
Unit test expanded code via public fns the macro wraps; or integration test macro output types.
($($rest:tt)*) => { compile_error!("hashmap! requires key => value"); }; as fallback arm.
#![recursion_limit = "256"] at crate root if deep recursive macro required.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026