在另一个宏中写入宏是可能的.例如,假设我定义了以下两个宏:

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.

Edit:在反复使用宏之后,我发现如果返回的宏没有收到任何参数,则高阶宏的工作原理与预期相同.例如,下面的code

#![feature(macro_rules)]

macro_rules! metamacro(
    ($i:ident) => (
        macro_rules! $i (
            () => ({println!("hello")})
        )
    );
)

metamacro!(foo)

fn main() {
    foo!();
}

打印hello

推荐答案

这是最近在#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.)

原因是宏扩展是"愚蠢的":它天真地解释和替换所有标记,甚至在嵌套的宏调用中(macro_rules!是一个宏调用).因此,它无法判断内部macro_rules!中的$e实际上是要保留为$e:它只是试图在扩展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);
}

打印12张.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

使用nom将任何空白、制表符、白线等序列替换为单个空白

如何在不安全的代码中初始化枚举 struct

PyReadonlyArray2到Vec T<>

为什么要在WASM库中查看Rust函数需要`#[no_mangle]`?

在泛型 struct 的字段声明中访问关联的Conant

如果成员都实现特征,是否在多态集合上实现部分重叠的特征?

Tokio_Postgres行上未显示退回特性的生存期,且生命周期 不够长

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

这个不安全的 Rust 代码有什么问题,所以它可以在 Windows 上运行,但不能在 Ubuntu 上运行?

为什么某些类型参数仅在特征边界中使用的代码在没有 PhantomData 的情况下进行编译?

如何基于常量在Rust中跳过一个测试

go 重并堆积MPSC通道消息

注释闭包参数强调使用高阶排定特征界限

如何在 Rust 中显式声明 std::str::Matches<'a, P> ?

为什么这段 Rust 代码会在没有递归或循环的情况下导致堆栈溢出?

为什么 `tokio::join!` 宏不需要 Rust 中的 `await` 关键字?

在线程中运行时,TCPListener(服务器)在 ip 列表中的服务器实例之前没有从客户端接受所有客户端的请求

当我不满足特征界限时会发生什么?

类型组的通用枚举