在Rust中的宏中创建闭包环境
我正在尝试实现这样的目标(简化): 它不起作用,因为在宏求值之前编译器会考虑在Rust中的宏中创建闭包环境,rust,rust-macros,Rust,Rust Macros,我正在尝试实现这样的目标(简化): 它不起作用,因为在宏求值之前编译器会考虑atest宏的参数: 错误[E0425]:在此范围内找不到值'x' -->src/main.rs:10:20 | 10 |最棒!(| | 5+x)); |^在此范围内找不到 有可能做到这一点吗?我的理解是宏是在编译之前展开的 有可能做到这一点吗?我的理解是宏是在编译之前展开的 宏在编译之前展开,但在解析之前不展开。原始输入代码已经被解析,宏在抽象语法树上操作,而不是在文本上。例如,闭包已经被理解为闭包,其自由变量已经绑
atest
宏的参数:
错误[E0425]:在此范围内找不到值'x'
-->src/main.rs:10:20
|
10 |最棒!(| | 5+x));
|^在此范围内找不到
有可能做到这一点吗?我的理解是宏是在编译之前展开的
有可能做到这一点吗?我的理解是宏是在编译之前展开的
宏在编译之前展开,但在解析之前不展开。原始输入代码已经被解析,宏在抽象语法树上操作,而不是在文本上。例如,闭包已经被理解为闭包,其自由变量已经绑定到其词汇范围内的变量
这与其他一些语言的宏不同,例如,宏对原始文本进行操作,如果不小心,它会让你把事情搞得一团糟。解释了为什么你所做的不起作用。这是所谓“宏卫生”的一部分:宏中声明的内容不能“泄漏”到周围的范围中
针对您面临的问题,一个常见的解决方法是将标识符的名称作为另一个参数传递到宏中:
macro_rules! atest {
($x:ident, $closure:tt) => {
let $x = 5;
println!("Result is {}", $closure())
};
}
fn main() {
atest!(x, (|| 5 + x));
}
这将起作用,因为命名x
会将其置于调用方的作用域中,即使声明在宏中
您可能会注意到闭包是不必要的,至少在本例中是这样——您可以将5+x
作为表达式传递给宏,并将其内联展开
macro_rules! atest {
($x:ident, $value:expr) => {
let $x = 5;
println!("Result is {}", $value)
};
}
你把这个宏叫做atest!(x,5+x)
,看起来有点像它自己的闭包。这可能会让你产生编写atest的想法!(|x | 5+x)
。这也会起作用,变量的作用域是闭包:
macro_rules! atest {
($closure:expr) => {
let x = 5;
println!("Result is {}", $closure(x))
};
}
工具书类
macro_rules! atest {
($closure:expr) => {
let x = 5;
println!("Result is {}", $closure(x))
};
}