Skip to content

Quick Ref: Macros ​

Updated Mar 2026

Macro Types ​

Declarative Macros (macro_rules!) ​

Basic Syntax ​

rust
macro_rules! say_hello {
    () => {
        println!("Hello!");
    };
}

say_hello!();  // Hello!

Fragment Specifiers ​

SpecifierMatchesExample
$x:exprExpression42, a + b, foo()
$x:identIdentifiermy_var, String
$x:tyTypei32, Vec<String>
$x:patPatternSome(x), _, 1..=5
$x:stmtStatementlet x = 5;
$x:blockBlock{ ... }
$x:itemItemfn foo() {}, struct S;
$x:pathPathstd::io::Error
$x:ttToken treeAny single token or (...)
$x:literalLiteral42, "hello", true
$x:lifetimeLifetime'a, 'static
$x:metaMeta itemderive(Debug), cfg(test)
$x:visVisibilitypub, 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: bar

Repetition ​

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 ​

MacroDescription
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_builder

Procedural 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

Built with VitePress | Rust SOP Documentation