高阶宏

时间:2014-07-12 23:39:00

标签: rust

生锈是否有可能编写一个创建其他宏的宏。例如,假设我定义了以下两个宏:

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

2 个答案:

答案 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!();
}