为什么Rust在多语句宏中找不到变量?

时间:2016-03-18 13:25:56

标签: macros rust

我有一个在unsafe块内调用的宏,它具有以下模式:

( $mrb:expr, $sig:expr, $args:ident, $name:ident : $t:tt) => {
    let $args = uninitialized::<*const MRValue>();
    let count = uninitialized::<i32>();

    mrb_get_args($mrb, $sig, args!($name, $t), &$args as *const *const MRValue,
                 &count as *const i32);
};

我用--pretty expanded,hygiene扩展了宏,它给了我:

let args /* 77#30 */ =
    uninitialized /* 789#28
        */::<*const MRValue /* 793#28 */>();
 let count /* 807#31 */ =
     uninitialized /* 789#28 */::<i32 /* 68#28 */>();
 mrb_get_args /* 805#28
     */(mrb /* 804#29 */, sig /* 797#29 */,
        &v /* 76#33 */ as *const i32 /* 68#34 */,
        &args /* 77#27 */ as
            *const *const MRValue /* 793#28 */,
        &count /* 807#28 */ as *const i32 /* 68#28 */);

args似乎是相同的(77),而且计数似乎也相同(807),但我仍然收到以下错误:

<mrusty macros>:24:20: 24:21 error: unresolved name `args`. Did you mean the macro `args!`? [E0425]
<mrusty macros>:24 mrb , sig , $ args , $ ( $ name : $ t ) , * ) ; conv ! (
                                  ^
<mrusty macros>:23:29: 24:48 note: in this expansion of args_rest! (defined in <mrusty macros>)
src/main.rs:12:47: 16:7 note: in this expansion of mrfn! (defined in <mrusty macros>)
<mrusty macros>:24:20: 24:21 help: run `rustc --explain E0425` to see a detailed explanation
<mrusty macros>:6:5: 6:10 error: unresolved name `count` [E0425]
<mrusty macros>:6 , & count as * const i32 ) ; } ; (
                  ^~~~~
<mrusty macros>:23:29: 24:48 note: in this expansion of args_rest! (defined in <mrusty macros>)
src/main.rs:12:47: 16:7 note: in this expansion of mrfn! (defined in  <mrusty macros>)
<mrusty macros>:6:5: 6:10 help: run `rustc --explain E0425` to see a detailed explanation

这看起来很可疑而且看起来像是一个错误,但在我提交Rust问题之前,我想要另外一双眼睛。

2 个答案:

答案 0 :(得分:4)

试试这个:

( $mrb:expr, $sig:expr, $args:ident, $name:ident : $t:tt) => {{
    let $args = uninitialized::<*const MRValue>();
    let count = uninitialized::<i32>();

    mrb_get_args($mrb, $sig, args!($name, $t), &$args as *const *const MRValue,
                 &count as *const i32);
}};

(注意宏扩展的主体被包裹在第二组大括号中)

我不记得你需要它的确切原因,但基本的想法是宏扩展块中的每个语句都扩展了它自己的卫生上下文,因此第一行中的$args不是与最后一行中的$args相同。但是,如果将所有语句放入单个块中,则卫生上下文将被共享,$args的两个扩展现在都引用相同的标识符。所以,这可能不是一个错误;这就是Rust的宏扩展如何运作。

答案 1 :(得分:0)

这不起作用的基本原因是因为多语句宏被破坏了。任何不返回值的宏(例如块)都只返回第一个语句。

macro_rules! example {
    ( $name:ident ) => {
        let mut $name = 0;
        let mut $name = 1;
    }
}

fn main() {
    example!(x);

    println!("{}", x);
}

此示例打印0,而不是1bug已关闭,但它可能会落在Rust 1.10。

同时,在适用的情况下使用块。