Frontend Labs
⋯

35. Macros: macro_rules! and what derive macros do

Rust macros operate on syntax trees, not text, so the problems of the C preprocessor (double evaluation, missing parentheses, name capture) do not occur.

use std::collections::HashMap;

// A literal syntax for maps: hashmap!{"a" => 1, "b" => 2}
macro_rules! hashmap {
    ($($k:expr => $v:expr),* $(,)?) => {{          // $(...),* repeats; $(,)? allows a trailing comma
        let mut m = HashMap::new();
        $( m.insert($k, $v); )*
        m
    }};
}

// Generate repetitive code: one newtype per ID kind, so a UserId cannot be passed as an OrderId.
macro_rules! id_type {
    ($($name:ident),+) => {
        $(
            #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
            pub struct $name(pub u64);
        )+
    };
}
id_type!(UserId, OrderId);

fn main() {
    let ports = hashmap! { "http" => 80, "https" => 443, };
    let u = UserId(7);
    let o = OrderId(7);
    // assert_eq!(u, o);  // compile error: different types
    println!("{:?} {u:?} {o:?}", ports.get("https"));
}

Procedural macros are Rust programs that run inside the compiler and take tokens in and produce tokens out. You use them all the time: #[derive(Debug, Serialize)], #[tokio::main], #[test]. cargo expand shows what they generate. Write your own only for real boilerplate across a codebase. They add compile time, and in a dependency they are code that runs on your machine at build time, which matters for supply-chain security (Ch 55).


Generated from real-life-rust-guide.md · 8 Oct 2026 16:36