Quick Ref: Macros ​
Updated Mar 2026Macro Types ​
Declarative Macros (macro_rules!) ​
Basic Syntax ​
rust
macro_rules! say_hello {
() => {
println!("Hello!");
};
}
say_hello!(); // Hello!Fragment Specifiers ​
| Specifier | Matches | Example |
|---|---|---|
$x:expr | Expression | 42, a + b, foo() |
$x:ident | Identifier | my_var, String |
$x:ty | Type | i32, Vec<String> |
$x:pat | Pattern | Some(x), _, 1..=5 |
$x:stmt | Statement | let x = 5; |
$x:block | Block | { ... } |
$x:item | Item | fn foo() {}, struct S; |
$x:path | Path | std::io::Error |
$x:tt | Token tree | Any single token or (...) |
$x:literal | Literal | 42, "hello", true |
$x:lifetime | Lifetime | 'a, 'static |
$x:meta | Meta item | derive(Debug), cfg(test) |
$x:vis | Visibility | pub, pub(crate), empty |
With Parameters ​
rust
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("Called: {}", stringify!($func_name));
}
};
}
create_function!(foo);
create_function!(bar);
foo(); // Called: foo
bar(); // Called: barRepetition ​
rust
// $(...)* — zero or more
// $(...)+ — one or more
// $(...),* — zero or more, comma-separated
macro_rules! vec_of_strings {
($($x:expr),* $(,)?) => {
vec![$($x.to_string()),*]
};
}
let v = vec_of_strings!["hello", "world", "rust"];
// vec!["hello".to_string(), "world".to_string(), "rust".to_string()]
// Multiple patterns
macro_rules! calculate {
(eval $e:expr) => {
let result: f64 = $e as f64;
println!("{} = {}", stringify!($e), result);
};
(eval $e:expr, $($rest:tt)*) => {
calculate!(eval $e);
calculate!($($rest)*);
};
}
calculate! {
eval 1 + 2,
eval 3 * 4,
eval (5 + 6) * 2
}Practical Example: HashMap Literal ​
rust
macro_rules! hashmap {
($($key:expr => $value:expr),* $(,)?) => {{
let mut map = ::std::collections::HashMap::new();
$(map.insert($key, $value);)*
map
}};
}
let scores = hashmap! {
"Alice" => 95,
"Bob" => 87,
"Charlie" => 92,
};Builder Pattern Macro ​
rust
macro_rules! builder {
($name:ident { $($field:ident: $type:ty),* $(,)? }) => {
struct $name {
$($field: $type),*
}
impl $name {
fn new() -> Self {
$name {
$($field: Default::default()),*
}
}
$(
fn $field(mut self, value: $type) -> Self {
self.$field = value;
self
}
)*
}
};
}
builder!(Config {
width: u32,
height: u32,
fullscreen: bool,
});
let config = Config::new()
.width(1920)
.height(1080)
.fullscreen(true);Common Standard Macros ​
| Macro | Description |
|---|---|
println!("x = {x}") | Print with newline |
print!("no newline") | Print without newline |
eprintln!("error!") | Print to stderr |
format!("s = {s}") | Return formatted String |
vec![1, 2, 3] | Create Vec |
todo!() | Placeholder, panics at runtime |
unimplemented!() | Not implemented yet |
unreachable!() | Should never be reached |
dbg!(expr) | Debug print with file/line, returns value |
assert!(cond) | Panic if false |
assert_eq!(a, b) | Panic if not equal |
assert_ne!(a, b) | Panic if equal |
cfg!(feature = "x") | Conditional compilation check |
env!("PATH") | Compile-time env variable |
include_str!("file.txt") | Include file as &str |
include_bytes!("file.bin") | Include file as &[u8] |
concat!("a", "b", "c") | Concatenate string literals |
stringify!(expr) | Convert tokens to string literal |
write!(buf, "fmt") | Write formatted to buffer |
writeln!(buf, "fmt") | Write formatted with newline |
Derive Macros ​
rust
// Standard derives
#[derive(Debug)] // {:?} formatting
#[derive(Clone)] // .clone() method
#[derive(Copy)] // Implicit copy (requires Clone)
#[derive(PartialEq)] // == and != comparison
#[derive(Eq)] // Total equality (requires PartialEq)
#[derive(PartialOrd)] // <, >, <=, >= (requires PartialEq)
#[derive(Ord)] // Total ordering (requires Eq + PartialOrd)
#[derive(Hash)] // Hashing (for HashMap keys)
#[derive(Default)] // Default::default() constructor
// Common external derives
#[derive(Serialize, Deserialize)] // serde
#[derive(Error)] // thiserror
#[derive(Parser)] // clap
#[derive(Builder)] // derive_builderProcedural Macros (Overview) ​
rust
// In a separate crate (proc-macro = true)
// Cargo.toml:
// [lib]
// proc-macro = true
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
// Derive macro
#[proc_macro_derive(MyTrait)]
pub fn my_trait_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let gen = quote! {
impl MyTrait for #name {
fn hello(&self) {
println!("Hello from {}!", stringify!(#name));
}
}
};
gen.into()
}
// Usage in another crate:
// use my_macro::MyTrait;
// #[derive(MyTrait)]
// struct Foo;
// Foo.hello(); // "Hello from Foo!"Debugging Macros ​
bash
# Expand macros to see generated code
cargo install cargo-expand
cargo expand # Expand all macros in crate
cargo expand module # Expand specific module
# In code
println!("{}", stringify!(my_macro!(args))); // See tokens as string