如何在 Rust 宏中引用局部变量?

6

我希望使用宏来生成函数体,但为了做到这一点,它们需要访问局部范围内的变量:

macro_rules! generate_func {
    ($name:ident) => {
        fn $name(param: i32) {
            generate_body!()
        }
    };
}

macro_rules! generate_body {
    () => {
        println!("{}", &param);
    }
}

generate_func!(foo);

error[E0425]: cannot find value `param` in this scope
  --> src/lib.rs:11:25
   |
11 |         println!("{}", &param);
   |                         ^^^^^ not found in this scope
...
15 | generate_func!(foo);
   | -------------------- in this macro invocation
   |
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

游乐场链接

很令人沮丧的是,这行代码不起作用,因为我可以运行 cargo-expand 并查看生成的代码是有效的:

fn foo(param: i32) {

    {
        ::std::io::_print(::core::fmt::Arguments::new_v1(&["", "\n"],
                                                         &match (&&param,) {
                                                              (arg0,) =>
                                                              [::core::fmt::ArgumentV1::new(arg0,
                                                                                            ::core::fmt::Display::fmt)],
                                                          }));
    }
}

因为有println!,所以这看起来有点杂乱,但你可以在其中看到有效的引用。

我甚至可以复制并粘贴扩展到我的源代码中,编译器也会接受它。肯定有某种方法可以实现所需的结果吧?

它似乎与以下内容相关:

但我不能确定我是否有完全相同的问题; 我的情况似乎更基础些。

1个回答

10
Rust宏是卫生的,可以防止一个作用域中的标识符泄漏到另一个作用域中并引起各种混乱。但是您可以通过从generate_func传递paramgenerate_body来解决这个特定的问题。
macro_rules! generate_func {
    ($name:ident) => {
        fn $name(param: i32) {
            generate_body!(param)
        }
    };
}

macro_rules! generate_body {
    ($param:ident) => {
        println!("{}", &$param);
    }
}

generate_func!(foo);

Playground上查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接