rust - 为什么我不能将捕获的 token 传递给嵌套宏?

标签 rust rust-macros

我见过的多个例子表明这应该是可能的,但显然不是:

lib.rs:

#![feature(trace_macros)]

#[macro_export]
macro_rules! inner_macro (
    (f32) => {"float"};
);

#[macro_export]
macro_rules! outer_macro {
    ($T:ty) => {
        inner_macro!($T)
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_nested() {
        trace_macros!(true);
        s1: String = String::from(outer_macro!(f32));
        s2: String = String::from(inner_macro!(f32));
        trace_macros!(false);
    }
}

运行 cargo test 给出以下输出:

error: no rules expected the token `f32`
  --> src/lib.rs:11:22
   |
4  | / macro_rules! inner_macro (
5  | |     (f32) => {"float"};
6  | | );
   | |__- when calling this macro
...
11 |           inner_macro!($T)
   |                        ^^ no rules expected the token `f32`
...
21 |           s1: String = String::from(outer_macro!(f32));
   |                                     ----------------- in this macro invocation

这很令人困惑,因为显然有一条规则需要 token f32

这两个宏的扩展轨迹也有注释。第一个不起作用:

= note: expanding `outer_macro! { f32 }`
= note: to `inner_macro ! ( f32 )`
= note: expanding `inner_macro! { f32 }`

而第二个是:

= note: expanding `inner_macro! { f32 }`
= note: to `"float"`

为什么 inner_macro! 的第一次扩展失败,而当它没有嵌套在另一个宏中时,完全相同的扩展却成功了?

编辑:如果我们手动执行替换,它会工作并给出预期的输出:

macro_rules! unknown {
    ($T:ty) => {
        inner_macro!(f32)
    }
}

最佳答案

some more reading 之后,事实证明这是一个典型的绊脚石实例。在第一次被捕获后,$T 获取了一个AST 节点 的值。替换 $T 不会放置 token ,它会放置那个 AST 节点。所以我希望是这样的:

inner_macro!(`f32` [token])

实际上是

inner_macro!(<Type>f32</Type>)

不幸的是,对于用户来说,这两个调用都以相同的方式被字符串化为 inner_macro! ( f32 )

执行此操作的正确方法是将要替换的 token 捕获为“ token 树”:

macro_rules! unknown {
    ($T:tt) => {
        inner_macro!($T)
    }
}

关于rust - 为什么我不能将捕获的 token 传递给嵌套宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53449947/

相关文章:

multithreading - “closure may outlive the current function”用作参数

rust - 有没有办法让一个特征在它扩展的另一个特征中为关联类型指定自己?

matrix - 是否可以编写一个可以转置矩阵的rust宏?

rust - 在Rust教程代码中获取 “error[E0599]: no method named write_fmt found”错误

hashmap - 如何遍历 Hashmap,打印键/值并删除 Rust 中的值?

rust - 如何从 Box<dyn T> 中获取 &dyn T

rust - 我可以在结构体内部调用宏吗?

rust - 如何使用一系列参数初始化结构

file - 如何使用 tokio::fs 复制文件

rust - 如何处理或测试某个类型是否是 Rust 宏中的选项?