I've been looking at rust macros recently and have found conflicting examples of macros using brackets (as laid out below). I'd like to know what the difference between each of these are and which one should be used when building macros. I'd also like to know whether any docs exist for any of this, as I can't find anything on the interwebs.
macro_rules! mac_a {
($x:ident,$y:expr) => { // <-- outer curlies
{ // <-- inner curlies
let $x = $y;
println!("{} {}", $x, $y);
}
};
}
macro_rules! mac_b {
($x:ident,$y:expr) => { // <-- outer curlies
// <-- no inner brackets / curlies
let $x = $y;
println!("{} {}", $x, $y);
};
}
// Does not compile
// macro_rules! mac_c {
// ($x:ident,$y:expr) => ( // <-- outer brackets
// ( // <-- inner brackets
// let $x = $y;
// println!("{} {}", $x, $y);
// )
// );
// }
macro_rules! mac_c2 {
($x:expr,$y:expr) => ( // <-- outer brackets
( // <-- inner brackets
println!("{} {}", $x, $y)
)
);
}
macro_rules! mac_d {
($x:ident,$y:expr) => ( // <-- outer brackets
// <-- no inner brackets / curlies
let $x = $y;
println!("{} {}", $x, $y);
);
}
fn main() {
mac_a!(a, 1);
mac_b!(b, 2);
// mac_c!(c, 3); // Does not compile
mac_c2!(3, 3);
mac_d!(d, 4);
}
All of the above except mac_c
compile, and there are differences between each hence the need for mac_c2
with ident
and let
removed. I don't know why they can't be included ¯\_(ツ)_/¯
AFAIK the outer curlies/brackets are equivalent and simply serve to delimit each individual macro expansion. OTOH the inner curlies/brackets are part of the generated code and their contents must therefore be legal for where they are used. If we expand the macro invocations in your main functions, we get:
fn main() {
// mac_a!(a, 1);
{ // <-- inner curlies
let a = 1;
println!("{} {}", a, 1);
}
// mac_b!(b, 2);
// <-- no inner brackets / curlies
let b = 2;
println!("{} {}", b, 2);
// mac_c!(c, 3); // Does not compile
( // <-- inner brackets
let c = 3; // Invalid code
println!("{} {}", c, 3);
)
// mac_c2!(3, 3);
( // <-- inner brackets
println!("{} {}", 3, 3)
)
// mac_d!(d, 4);
// <-- no inner brackets / curlies
let d = 4;
println!("{} {}", d, 4);
}
Note BTW that there is therefore a difference for what variables are still around after the macro invocations:
fn main() {
mac_a!(a, 1);
mac_b!(b, 2);
// mac_c!(c, 3); // Does not compile
mac_c2!(3, 3);
mac_d!(d, 4);
// println!("{}", a); // Does not compile because the `let a = ...` was done inside curlies
println!("{} {}", b, d); // Work because `let b = ...` and `let d = ...` were inserted in the current scope
}