2016-01-23 2 views
4

Я хотел бы компилировать код похож на этот минимальный тестовый пример:Почему этот макрос приводит к ошибке неразрешенного имени?

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 

Другие макросы, которые вводят переменные работы; в чем проблема?

ответ

6

Это потому, что macro_rules! является своего рода сломанным, когда дело доходит до макросов, которые расширяются до операторов.

Проблема в основном состоит в том, что он считает каждое заявление самостоятельно для целей гигиены. Другими словами, третий оператор буквально не может видеть привязку, определенную в первой строке.

В некоторых случаях, вы можете обойти эту проблему, обернув заявления в блоке:

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

Это решает его и заставляет меня понять проблему. (Я не хочу писать, что это имеет смысл :)) –

1

Ваш fn bar не имеет ничего имени saved в области действия на сайте вызова.

+0

Когда я ввожу строку 'пусть сохранённый = 3' в строке() до макро, он компилирует, даже хотя те, сохраненные внутри макроблока, не имеют ничего общего с внешним (кроме того, что он затеняет его). –

+0

Правильно. Макросы Rust's [_hygienic_] (https://doc.rust-lang.org/book/macros.html#hygiene). Одним из последствий макрогигиены является неспособность вводить такие переменные в область вызова. Однако вы возвращаете значения _can. – jwilm

+0

Это не совсем так, так как ваша ссылка говорит: «Это позволяет использовать привязки и метки меток, но не для элементов. Таким образом, следующий код компилируется:». См. Например https://github.com/rust-lang-nursery/lazy-static.rs. –