Rust宏嵌套虽然很强大,但也很容易出现问题。简单嵌套情况下可能出现的问题是编译器无法解析其中一个宏的输出。更加复杂的情况可能会导致编译错误或 panic。
以下是一个例子,展示了一个简单的嵌套 Rust 宏,用于生成一些 HTML 代码:
macro_rules! html {
($tag:ident) => { println!("<{}>{}>", stringify!($tag), stringify!($tag)); };
($tag:ident, $($contents:tt)*) => {
println!("<{}>", stringify!($tag));
html!($($contents)*);
println!("{}>", stringify!($tag));
};
}
macro_rules! body {
($($contents:tt)*) => { html!(body, $($contents)*) };
}
fn main() {
html!(body, html!(p, "Hello, world!"));
}
这里定义了 html! 和 body! 两个宏。body! 简单地将参数转换为 html!(body, ...)。 当我们在主函数中调用 html!(body, html!(p, "Hello, world!")) 时,我们会得到 "error: no rules expected this token in macro call" 编译错误,因为 Rust 编译器无法解析 html!(p, "Hello, world!") 的输出。
解决此错误的简单方法是明确 html! 宏的输出,显式地使用 {} 将其包裹。修改后的代码可如下:
macro_rules! html {
($tag:ident) => { format!("<{}>{}>", stringify!($tag), stringify!($tag)) };
($tag:ident, $($contents:tt)*) => {
format!(
"<{}>{}{}>",
stringify!($tag),
html!($($contents)*),
stringify!($tag)
)
};
}
macro_rules! body