Macros

Macro Repetition

Macro repetition ($( ... )sep*, +, or ?) allows a macro_rules! pattern to match zero, one, or arbitrarily many occurrences of a token pattern and expand them in lock-step inside the transcriber.

Repetition Operators and Syntax

$(  pattern_to_repeat  )  separator  quantifier
^^  ^^^^^^^^^^^^^^^^^  ^  ^^^^^^^^^  ^^^^^^^^^^
│         body         │  optional   *, +, or ?
└── repetition group ──┘  (, ; =>)
Quantifier Meaning Separator Allowed? Example Matcher
* Zero or more repetitions ($0, 1, 2, \dots$) Yes (e.g., , or ;) $($x:expr),*
+ One or more repetitions ($1, 2, 3, \dots$) Yes (e.g., , or ;) $($x:expr),+
? Zero or one repetition (optional, $0$ or $1$) No $(,)? (optional trailing comma)

Supporting Optional Trailing Commas ($(,)?)

In ($($x:expr),*), the separator , is matched between elements, so my_vec![1, 2,] with a trailing comma fails unless you append $(,)? after the repetition group:

macro_rules! hash_map {
    // Empty map:
    () => {
        std::collections::HashMap::new()
    };
    // One or more `key => value` pairs with optional trailing comma `$(,)?`:
    ( $( $key:expr => $val:expr ),+ $(,)? ) => {{
        let mut map = std::collections::HashMap::new();
        $(
            map.insert($key, $val);
        )+
        map
    }};
}

fn main() {
    let codes = hash_map! {
        "OK" => 200,
        "Not Found" => 404, // Trailing comma accepted via `$(,)?`
    };

    println!("OK = {}, Not Found = {}", codes["OK"], codes["Not Found"]);
}
OK = 200, Not Found = 404

Lock-Step Expansion of Multiple Repeated Variables

When a matcher captures two or more repeated metavariables ($k and $v) at the same repetition depth, you can expand them together inside the same $( ... )* loop or separately in different $( ... )* loops:

macro_rules! zip_tuples {
    ( [ $($a:expr),* ] , [ $($b:expr),* ] ) => {
        vec![ $( ($a, $b) ),* ]
    };
}

fn main() {
    let paired = zip_tuples!([1, 2, 3], ["one", "two", "three"]);
    println!("Paired: {paired:?}");
}
Paired: [(1, "one"), (2, "two"), (3, "three")]

(If the two lists passed to zip_tuples! have different lengths, the compiler emits a compile-time error: meta-variable 'a' repeats 3 times, but 'b' repeats 2 times.)