0Pricing
Learn Rust Coding · Lesson

Declarative Macros (`macro_rules!`)

Learn to write declarative macros for abstracting repetitive code patterns and generating code at compile time.

Declarative Macros (`macro_rules!`) is a free Learn Rust Coding lesson on CoddyKit — lesson 1 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What are Rust Macros?

Macros are a way to write code that writes code! They're like functions, but they operate on syntax trees (the structure of your code) instead of values.

  • They help abstract repetitive code.
  • They enable Domain Specific Languages (DSLs) within Rust.
  • They run at compile time, expanding into regular Rust code before compilation.

Declarative Macro Syntax

Rust's declarative macros use the macro_rules! keyword. They define a set of rules that match specific patterns of Rust code.

Think of it as pattern matching for code snippets. When the compiler sees a macro invocation, it tries to match the input to one of the rules you've defined.

Your First `macro_rules!`

Let's create a very simple macro that prints a greeting. Notice the macro_rules! keyword and the () => {} syntax, defining a rule with no input pattern.

Try running this example:

macro_rules! greet {
    () => {
        println!("Hello from a macro!");
    };
}

fn main() {
    greet!(); // Call our macro!
}

Capturing Input with Designators

Macros can take input using "designators." These tell the macro what kind of Rust syntax it should expect to capture.

  • $expr: An expression (e.g., 1 + 2, "hello")
  • $ident: An identifier (e.g., variable name, function name)
  • $ty: A type (e.g., i32, String)
  • $block: A block of code (e.g., { ... })
  • ...and many more!

Macros Taking Arguments

Here's a macro that takes an expression ($e:expr) and prints its value. The :expr is the designator.

The captured $e then becomes available for use in the macro's body. The stringify! macro converts the expression into its string representation.

macro_rules! debug_print {
    ($e:expr) => {
        println!("Debug: {} = {:?}", stringify!($e), $e);
    };
}

fn main() {
    let x = 10;
    debug_print!(x + 5);
    debug_print!("Rust macros are fun");
}

Handling Multiple Inputs

What if you want a macro to take multiple arguments of the same type? You can use repetition operators: $()*.

  • $(): The content inside is the pattern to repeat.
  • *: Zero or more repetitions.
  • +: One or more repetitions.
  • You can also specify a separator, like $(...),* for comma-separated items.

Macro with Repetitive Arguments

Let's create a macro that takes multiple expressions, separated by commas, and prints each one individually. This is powerful for creating list-like structures.

macro_rules! print_all {
    ( $( $x:expr ),* ) => {
        $( // This $(...)* repeats the `println!` call
            println!("Item: {:?}", $x);
        )*
    };
}

fn main() {
    print_all!(1, "hello", true, 3.14);
    print_all!("Just one item");
}

Understanding Macro Hygiene

Rust's macros are "hygienic." This means that variables defined inside a macro won't accidentally clash with variables outside the macro, even if they have the same name.

The compiler renames things internally during expansion to prevent unintended side effects, making macros safer and more predictable to use.

How to Debug Macros

Sometimes macros don't expand as you expect. Rust provides a way to see the expanded code:

  • Run cargo expand (requires installing the cargo-expand tool)
  • Use rustc --pretty expanded directly on your source file.

This shows you the raw Rust code that your macro generates, which is invaluable for debugging and understanding complex macro behavior!

Macro Pattern Matching Quiz

Consider the following macro definition:

macro_rules! make_tuple {
    ( $x:expr, $y:expr ) => {
        ($x, $y)
    };
}

Which of the following lines would successfully compile and use the make_tuple! macro?

Recap: Declarative Macros

In this lesson, you learned about declarative macros using macro_rules!:

  • They generate code at compile time, abstracting repetitive patterns.
  • They use pattern matching to capture input based on syntax.
  • Designators like $expr, $ident specify what kind of syntax to expect.
  • Repetition operators like $()* handle multiple arguments with flexible separators.
  • Macros are hygienic, preventing accidental name conflicts.

Macros are a powerful tool for reducing boilerplate and creating flexible, ergonomic APIs in Rust!

Frequently asked questions

Is the “Declarative Macros (`macro_rules!`)” lesson free?

Yes — the full text of “Declarative Macros (`macro_rules!`)” is free to read here on the web, and the Learn Rust Coding course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.

What will I learn in “Declarative Macros (`macro_rules!`)”?

Learn to write declarative macros for abstracting repetitive code patterns and generating code at compile time. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Learn Rust Coding?

No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 3, so you can start here or from the beginning and move at your own pace.

How long does the “Declarative Macros (`macro_rules!`)” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Learn Rust Coding lesson?

Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Declarative Macros (`macro_rules!`)
  2. Procedural Macros: Derive, Function
  3. Interacting with Unsafe Rust
← Back to Learn Rust Coding