A Rust macro writes code for you. You have probably used one already: `println!` is a macro, and the `!` marks a macro call. Unlike a regular function, a macro can produce code—such as a struct definition—for the compiler to check afterward. That makes macros useful when a function cannot remove repetitive typing. section 1.3 section 22.1
macro_rules! give_six {
() => {
6
};
}
fn main() {
let six = give_six!();
println!("{}", six);
}
Start small: `macro_rules!` defines `give_six`. Its `()` rule accepts an empty call, and `give_six!()` produces the expression `6`. section 22.2
The rules resemble match arms, but they match input tokens rather than running a `match` expression. Different rules can produce different kinds of code. If a call fits no rule, the compiler reports an error such as “no rules expected the token.” And if a rule produces invalid Rust, the error appears when that macro is called—not merely when it is defined. section 22.2
Once literal inputs make sense, give parts of the input names:
- `$input:expr` captures an expression; `$input:stmt` captures a statement instead. A `let` statement does not fit an `expr` rule. section 22.2
- `$name:ident` captures an identifier, while `$input:tt` captures a token tree. These names can be used in the code the rule produces. section 22.2
- `$($input:tt),*` accepts zero or more comma-separated inputs; changing `*` to `+` requires at least one. section 22.2
macro_rules! make_a_function {
($name:ident, $($input:tt),+) => { #1
fn $name() {
let output = stringify!($($input),+); #2
println!("{}", output);
}
};
}
fn main() {
make_a_function!(print_it, 5, 5, 6, I); #3
print_it();
make_a_function!(say_its_nice, this, is, really, nice); #4
say_its_nice();
}
Here the identifier becomes a function name, and repeated inputs become its printed text. Two calls generate two functions without writing each function by hand. section 22.2
Reading a macro can also clarify how to call it. The standard-library `write!` rule accepts a destination followed by any number of token trees; `todo!` has rules for an empty call or supplied arguments. Some library macros eventually reach compiler-built-in parts whose details are not visible, so understanding their accepted inputs is a useful stopping point. section 22.3
macro_rules! derive_try_from {
($type:ident, $length:expr) => {
impl TryFrom<&str> for $type {
type Error = String; #1
fn try_from(value: &str) -> Result<Self, Self::Error> {
let length = $length; #2
if value.chars().count() > length {
Err(format!("Must be no longer than {length}"))
} else {
Ok(Self(value.to_string()))
}
}
}
};
}
A practical use: this rule takes a type name and a maximum length, then generates a `TryFrom<&str>` implementation. Calls for several string-holder types can share the same conversion logic. section 22.4
Macros are common to use but rarely necessary to write. Reach for one when it can generate repeated code that an ordinary function cannot; learn the syntax by reading existing rules and modifying small examples. section 22.4 section 22.5








