问题描述
我想使用宏来生成函数的主体,但要这样做,它们需要访问局部作用域中的变量:
macro_rules! generate_func {
($name:ident) => {
fn $name(param: i32) {
generate_body!()
}
};
}
macro_rules! generate_body {
() => {
println!("{}",¶m);
}
}
generate_func!(foo);
error[E0425]: cannot find value `param` in this scope
--> src/lib.rs:11:25
|
11 | println!("{}",¶m);
| ^^^^^ 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 (&¶m,) {
(arg0,) =>
[::core::fmt::ArgumentV1::new(arg0,::core::fmt::Display::fmt)],}));
}
}
(由于println!
有点混乱,但是您可以在其中看到有效的引用)
我什至可以将扩展复制并粘贴到我的源代码中,编译器会接受它。当然有某种方法可以达到预期的结果?
似乎与以下内容有关:
- "cannot find value `a` in this scope" in Rust macro
- https://github.com/dtolnay/proc-macro-hack/issues/15
但是我不确定我是否有完全相同的问题;我的情况似乎更基本。
解决方法
Rust宏为hygienic,可防止标识符从一个作用域泄漏到另一个作用域并引起各种混乱。但是您可以通过将param
从generate_func
传递到generate_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上看到它。