【问题标题】:Why does this macro result in an unresolved name error?为什么这个宏会导致未解析的名称错误?
【发布时间】:2016-01-23 15:24:31
【问题描述】:

我想编译类似于这个最小测试用例的代码:

macro_rules! why {
    ( [ $saved:ident ] $body:block ) => {
        let $saved = 3;
        $body
        let _a = $saved;
    }
}

fn bar() {
    why!([saved] {
    });
}

fn main() {
}

当我尝试编译它时,我收到以下错误:

src/main.rs:10:20: 10:21 error: unresolved name `saved` [E0425]
src/main.rs:10         why!([saved] {
                                  ^
src/main.rs:10:9: 11:12 note: in this expansion of why! (defined in src/main.rs)
src/main.rs:10:20: 10:21 help: run `rustc --explain E0425` to see a detailed explanation

其他引入变量的宏工作;这里有什么问题?

【问题讨论】:

    标签: macros rust


    【解决方案1】:

    这是因为macro_rules! 在涉及扩展为语句的宏时有点坏了。

    问题基本上在于,出于卫生的目的,它独立地考虑每个语句。换句话说,第三条语句实际上看不到第一行定义的绑定。

    在某些情况下,您可以通过将语句包装在一个块中来解决此问题:

    macro_rules! why {
        ( [ $saved:ident ] $body:block ) => {
            {
                let $saved = 3;
                $body
                let _a = $saved;
            }
        }
    }
    

    【讨论】:

    • 这解决了它并让我理解了这个问题。 (我不想写,这是有道理的:))
    【解决方案2】:

    您的fn bar 在调用站点的范围内没有任何名为saved 的内容。

    【讨论】:

    • 当我在宏之前的 bar() 中引入一行 let saved = 3 时,它会编译,即使保存在宏块内的 te 与外部无关(除了遮蔽它)。
    • 没错。 Rust 的宏是 hygienic。宏观卫生的影响之一是无法将类似的变量引入调用范围。但是,您可以返回值。
    • 这并不完全正确,正如您的链接所说:“这适用于 let 绑定和循环标签,但不适用于项目。因此以下代码确实可以编译:”。参见例如github.com/rust-lang-nursery/lazy-static.rs。
    猜你喜欢
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-03-23
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多