在 Rust 的宏中创建闭包环境 [英] Creating environment for closure in a macro in Rust

查看:45
本文介绍了在 Rust 的宏中创建闭包环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现这样的目标(简化):

I'm trying to achieve something like this (simplified):

macro_rules! atest {
    ($closure:tt) => {
        let x = 5;
        println!("Result is {}", $closure())
    };
}

fn main() {
    //let x = 50;
    atest!((|| 5 + x));
}

它不起作用,因为在宏计算之前编译器会考虑 test 宏的参数:

It does not work because the argument to the atest macro is considered by the compiler before macro evaluation:

error[E0425]: cannot find value `x` in this scope
  --> src/main.rs:10:20
   |
10 |     atest!((|| 5 + x));
   |                    ^ not found in this scope

有可能完成这项工作吗?我的理解是宏是在编译前展开的.

Is it possible to make this work? My understanding was that macros are expanded before compilation.

推荐答案

Peter 的回答 解释了您为什么要这样做不会工作.这是所谓的宏观卫生"的一部分:在宏中声明的东西不能泄漏"到周围的范围.

Peter's answer explains why what you're doing won't work. This is part of what's referred to as "macro hygiene": things declared inside macros can't "leak" into the surrounding scope.

解决您面临的问题的常见方法是将标识符的名称作为另一个参数传递给宏:

A common workaround for the problem you're facing is to pass the name of the identifier into the macro as another argument:

macro_rules! atest {
    ($x:ident, $closure:tt) => {
        let $x = 5;
        println!("Result is {}", $closure())
    };
}

fn main() {
    atest!(x, (|| 5 + x));
}

这会起作用,因为命名 x 会将它放在调用者的范围内,即使声明在宏内部.

This will work because naming x puts it in the caller's scope, even though the declaration is inside the macro.

您可能会注意到闭包是不必要的,至少在这个例子中——您可以将 5 + x 作为表达式传递给宏并使其内联扩展.

You might notice that the closure is kind of unnecessary, at least in this example -- you could just pass 5 + x as an expression to the macro and have it expanded inline.

macro_rules! atest {
    ($x:ident, $value:expr) => {
        let $x = 5;
        println!("Result is {}", $value)
    };
}

你把这个宏称为 atest!(x, 5 + x),它看起来有点像它自己的闭包.这可能会给你写 test!(|x| 5 + x) 的想法.这也可以工作,变量范围为闭包:

You call this macro like atest!(x, 5 + x), which looks a little bit like a closure of its own. That might give you the idea of writing atest!(|x| 5 + x) instead. And that will also work, with a variable scoped to the closure:

macro_rules! atest {
    ($closure:expr) => {
        let x = 5;
        println!("Result is {}", $closure(x))
    };
}

参考文献

  • Rust pt1 中的宏
  • 这篇关于在 Rust 的宏中创建闭包环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆