macro_rules!
Declarative macros allow us to take syntactic fragments of the Rust language as input and then return raw source code. A bonus of declarative macros is that they allow arbitrary repetition of code.
macro_rules! make_it {() => {// Everything placed here will be generated in source code when the macro is called.}}
When working with macros, parameters are referred to as Metavariables, and their respective types are called fragment-specifiers.
We can declare our metavariables in a similar manner as function parameters. However, metavariables must start with $
, and there can be no spaces between the metavariable, its fragment-specifier, and the separating :
.
macro_rules! make_it {($happen:expr) => {println!("{}", $happen)}}make_it!("we did it!");make_it!(usize::MAX);// Here we have let our macro accept any expression which we can represent with the metavariable `$happen` and passing it to `println!()`.
Macros make it easy to repeat fragments of code. We can repeat code by enclosing it within $()
followed by either a *
, +
, or ?
.
*
will accept any number of repetitions, including none.+
will accept any number of repetitions but requires at least one.?
will accept one or no repetitions.By adding the ,
to create $(),+
in our input, we are stating that the repeated items are delimited by ,
. We can use any single token as a delimiter that is valid in the context of nearby metavariables.
macro_rules! make_it {( $var:ident => $($count:expr),+) => {$($var.push($count);)+}}let mut count = vec![];make_it![count => u8::MIN, 1, 2];println!("{count:?}");
Macros can be exported and used anywhere in our crate with the #[macro_export]
attribute.
This also makes the macro visible to other crates when importing our crate as a dependency.
#[macro_export]macro_rules! make_it {( $var:ident => $($count:expr),+) => {$($var.push($count);)+}}// Alternatively, we can also export all macros contained within a module with the #[macro_use] attribute#[macro_use]mod macros;