Declarative macros
Source
Initialize a new workspace with cargo init --lib
.
#![allow(unused)] fn main() { pub fn declarative_macro_vec_empty() -> Vec<i32> { let vec: Vec<i32> = vec![]; vec } pub fn declarative_macro_vec_repeat() -> Vec<i32> { let vec: Vec<i32> = vec![1; 10]; vec } pub fn declarative_macro_vec_list() -> Vec<i32> { let vec: Vec<i32> = vec![1, 2, 3]; vec } }
Declarative macros are defined with the macro_rules!
language construct and they work through pattern matching on the syntax tree. The implementation handling the macro compilation can be found here and here.
Since declarative macros can be expanded to arbitrary Rust code based on the implementation of the macro, we will focus on the expanded Rust code rather than the generated binary files in this chapter.
If we look at the vec!
macro as an example, we see that it has 3 arms:
- the 1. one matching
vec![]
- the 2. one matching
vec![1; 10]
- the 3. one matching
vec![1, 2, 3]
#![allow(unused)] fn main() { macro_rules! vec { () => ( $crate::vec::Vec::new() ); ($elem:expr; $n:expr) => ( $crate::vec::from_elem($elem, $n) ); ($($x:expr),+ $(,)?) => ( <[_]>::into_vec( // Using the intrinsic produces a dramatic improvement in stack usage for // unoptimized programs using this code path to construct large Vecs. $crate::boxed::box_new([$($x),+]) ) ); } }
declarative_macro_vec_empty
#![allow(unused)] fn main() { pub fn declarative_macro_vec_empty() -> Vec<i32> { let vec: Vec<i32> = vec![]; vec } }
$ cargo expand
...
pub fn declarative_macro_vec_empty() -> Vec<i32> {
let vec: Vec<i32> = ::alloc::vec::Vec::new();
vec
}
declarative_macro_vec_repeat
#![allow(unused)] fn main() { pub fn declarative_macro_vec_repeat() -> Vec<i32> { let vec: Vec<i32> = vec![1; 10]; vec } }
$ cargo expand
...
pub fn declarative_macro_vec_repeat() -> Vec<i32> {
let vec: Vec<i32> = ::alloc::vec::from_elem(1, 10);
vec
}
declarative_macro_vec_list
#![allow(unused)] fn main() { pub fn declarative_macro_vec_list() -> Vec<i32> { let vec: Vec<i32> = vec![1, 2, 3]; vec } }
$ cargo expand
...
pub fn declarative_macro_vec_list() -> Vec<i32> {
let vec: Vec<i32> = <[_]>::into_vec(::alloc::boxed::box_new([1, 2, 3]));
vec
}