Creating environment for closure in a macro in Rust

前端 未结 2 1938
忘掉有多难
忘掉有多难 2021-01-04 18:20

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

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


        
2条回答
  •  我在风中等你
    2021-01-04 18:52

    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));
    }
    

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

    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)
        };
    }
    

    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))
        };
    }
    

    References

    • Macros in Rust pt1

提交回复
热议问题