I\'m reading a book about Rust, and start playing with Rust macros. All metavariable types are explained there and have examples, except the last one – tt
. Acco
That's a notion introduced to ensure that whatever is in a macro invocation correctly matches ()
, []
and {}
pairs. tt
will match any single token or any pair of parenthesis/brackets/braces with their content.
For example, for the following program:
fn main() {
println!("Hello world!");
}
The token trees would be:
fn
main
()
{ println!("Hello world!"); }
println
!
("Hello world!")
"Hello world!"
;
Each one forms a tree where simple tokens (fn
, main
etc.) are leaves, and anything surrounded by ()
, []
or {}
has a subtree. Note that (
does not appear alone in the token tree: it's not possible to match (
without matching the corresponding )
.
For example:
macro_rules! {
(fn $name:ident $params:tt $body:tt) => { /* … */ }
}
would match the above function with $name → main
, $params → ()
, $body → { println!("Hello world!"); }
.
Token tree is the least demanding metavariable type: it matches anything. It's often used in macros which have a “don't really care” part, and especially in macros which have a “head” and a “tail” part. For example, the println!
macros have a branch matching ($fmt:expr, $($arg:tt)*)
where $fmt
is the format string, and $($arg:tt)*
means “all the rest” and is just forwarded to format_args!
. Which means that println!
does not need to know the actual format and do complicated matching with it.