Skip to content
Free public beta until December 4, 2026: every course is open, no card needed. After that, the first chapter of each course stays free and full access is a one-time $39 ($19 for up to 100 founding members chosen for helpful feedback). Your progress is kept. How the beta works

Recipe

Write a macro_rules! macro

Use when: a job on Section 1's list (any number of arguments, new syntax, generated items, source text) that you'd otherwise copy and paste

Goal: a macro whose expansion is the code you would have written by hand

Taught in Declarative macros with macro_rules!

  1. 1

    Write out, as ordinary Rust, the code you want for two different calls.

    Example

    For readings!{"bench A" => 21.5} and a three-bench call: a block that makes a map, one map.insert(..) per bench, then map.

    Why: the macro's output is ordinary Rust; you need to know that code before you can template it.

  2. 2

    Circle the parts that differ between the two expansions. Give each one a name and a fragment specifier.

    • the part is a name the macro will define or read — ident.
    • the part is a value — expr (or literal if only written-out values make sense).

    Why: the fixed parts become the transcriber; the varying parts become metavariables.

  3. 3

    Write the call's shape with the metavariables in place. Wrap repeated parts in $( ... ),* or $( ... ),+.

    Why: the matcher is the call's grammar; * or + decides whether an empty call is allowed.

  4. 4

    Paste the hand-written expansion, replace the varying parts with the metavariables, and wrap the repeated lines in $( ... )*. Use {{ }} if the result must be one expression.

    Why: each repeated variable must appear inside a repetition of the same depth.

  5. 5

    Call it with zero, one and several items. When a result surprises you, read the expansion.

    Why: the compiler checks each expansion; an unusual call (the empty one especially) can produce an error or warning the normal calls don't.

Common mistakes

  • Using * when an empty call makes no sense (use +).
  • Forgetting the inner braces: the expansion is then several statements, not one expression.
  • Putting something other than =>, , or ; after an expr variable.