A macro generates Rust code from code supplied at its call site. It is useful when a function cannot conveniently express the desired syntax or when many definitions repeat the same pattern. Declarative macros use `macro_rules!`; procedural macros are a separate, more complex system. section 5.1 section 5.1.2
A call such as `println!("hello")` has a mandatory `!`, distinguishing it from a function call. A `macro_rules!` definition contains matcher-and-expansion arms: `macro_rules! noop_macro { () => {}; }` matches an empty call. Matchers inspect Rust code fragments, not the results of executing that code. For example, `$e:expr` matches an expression and `$s:stmt` matches a statement; a call matching no arm produces a compiler error. section 5.1.1
Forward a variable number of tokens
`macro_rules! special_println { ($($arg:tt)*) => { println!($($arg)*) }; }` forwards its input to `println!`. Here `tt` matches token trees, `$(…)*` allows zero or more repetitions, and the expansion repeats the captured input. This is a practical reason to choose a macro over a function: the call can accept variadic arguments. section 5.1.2
macro_rules! var_print {
($($v:ident),*) => { #1
println!(
concat!($(stringify!($v),"={:?} "),*), $($v),* #2
)
};
}
The `var_print!` listing matches comma-separated identifiers and expands them into printed names and debug-formatted values, showing how repetition can generate both labels and arguments. section 5.1.2
Macros can also provide a small domain-specific language. `lazy_static!` matches declarations shaped like `static ref NAME: TYPE = EXPR;`, forwards them to an internal macro, and recursively processes the remaining declarations until an empty matcher ends the expansion. Keep such syntax simple enough to follow. section 5.1.3
Listing 5.5 Adding with_str! and with! macros to BicycleBuilder
macro_rules! with_str {
($name:ident, $func:ident) => { #1
fn $func(&mut self, $name: &str) {
self.bicycle.$name = $name.into() #2
}
};
}
macro_rules! with {
($name:ident, $func:ident, $type:ty) => { #3
fn $func(&mut self, $name: $type) {
self.bicycle.$name = $name
}
};
}
impl BicycleBuilder {
with_str!(make, with_make);
with_str!(model, with_model);
with!(size, with_size, i32);
with_str!(color, with_color);
}
The builder listing replaces repeated methods with two small macros: `with_str!` accepts `&str` and stores a `String`, while `with!` accepts a specified field type. Separate macros keep the difference explicit. section 5.3.3
Use macros to remove genuinely repetitive code, not to hide unclear design. For builders, an existing solution such as `derive_builder` may save more work than maintaining custom macros. section 5.1 section 5.3.3








