生锈是否有可能编写一个创建其他宏的宏。例如,假设我定义了以下两个宏:
macro_rules! myprint(
($a:expr) => (print!("{}", $a))
)
macro_rules! myprintln(
($a:expr) => (println!("{}", $a))
)
由于两个宏重复了很多代码,我可能想编写一个宏来生成宏。
我试图生成这样的meta macro。
#![feature(macro_rules)]
macro_rules! metamacro(
($i:ident) => (
macro_rules! $i (
($a:expr) => ({println!("hello {}", $a)})
)
);
)
metamacro!(foo)
fn main() {
foo!(1i);
}
但是会出现以下错误:
<anon>:6:13: 6:14 error: unknown macro variable `a`
<anon>:6 ($a:expr) => ({println!("hello {}", $a)})
^
playpen: application terminated with error code 101
Program ended.
编辑:在更多地使用宏之后,我发现如果返回的宏没有接收到任何参数,则更高阶的宏按预期工作。例如,以下code
#![feature(macro_rules)]
macro_rules! metamacro(
($i:ident) => (
macro_rules! $i (
() => ({println!("hello")})
)
);
)
metamacro!(foo)
fn main() {
foo!();
}
打印hello
答案 0 :(得分:12)
最近在#34925中实现了这一点。下面的答案是指旧版本的Rust。
这是#6795和#6994,目前无法直接使用。例如。人们会尝试的第一件事是
#![feature(macro_rules)]
macro_rules! define {
($name: ident, $other: ident) => {
macro_rules! $name {
($e: expr) => {
$other!("{}", $e)
}
}
}
}
define!{myprintln, println}
define!{myprint, print}
fn main() {}
但是
失败了so8.rs:6:13: 6:14 error: unknown macro variable `e`
so8.rs:6 ($e: expr) => {
^
(提交#15640关于指向(
而不是$e
的插入符号。{/ p>
原因是宏扩展是&#34; dumb&#34;它天真地解释和替换所有令牌,甚至在嵌套的宏调用中(并且macro_rules!
是一个宏调用)。因此,它无法告诉内部$e
内的macro_rules!
实际上是保留为$e
:它只是在展开时尝试替换它们{ {1}}。
可能尝试的第二件事是将额外的参数传递给define
以放置在内部定义中,以便define
不会直接出现在嵌套调用中:
$e
也就是说,我添加了#![feature(macro_rules)]
macro_rules! define {
($name: ident, $other: ident, $($interior: tt)*) => {
macro_rules! $name {
($($interior)*: expr) => {
$other!("{}", $($interior)*)
}
}
}
}
define!{myprintln, println, $e}
define!{myprint, print, $e}
fn main() {}
以允许捕获$interior: tt
。 $e
代表令牌树,它是非分隔符原始令牌(例如tt
或$
)或由匹配分隔符(例如some_ident
)包围的令牌序列。不幸的是,似乎扩展足以让(foo + bar fn "baz")
扩展得到扩展:
$e
当嵌套宏本身没有参数时,它工作正常,因为没有嵌套的so8.rs:8:13: 8:14 error: unknown macro variable `e`
so8.rs:8 ($($interior)*: expr) => {
^
非终端,因此扩展阶段没有遇到上述定义问题。
最后,您可以获得一些代码共享,因为您可以按名称扩展到宏调用:
$...
打印#![feature(macro_rules)]
macro_rules! my {
($name: ident, $e: expr) => {
$name!("{}", $e)
}
}
fn main() {
my!(print, 1i);
my!(println, 2i);
}
。
答案 1 :(得分:0)
这是一个有效的例子,也许是你的起点:
#![feature(macro_rules)]
macro_rules! metamacro(
($i:ident) => (
macro_rules! $i (
() => ({println!("hello!")})
)
);
)
metamacro!(hello)
fn main() {
hello!();
}