Создание среды для замыкания в макросе в Rust - PullRequest
0 голосов
/ 13 мая 2018

Я пытаюсь добиться чего-то вроде этого (упрощенно):

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

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

Это не работает, потому что аргумент макроса atest рассматривается компилятором перед оценкой макроса:

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

Можно ли заставить эту работу работать? Насколько я понимаю, макросы раскрываются перед компиляцией.

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Ответ Питера объясняет, почему то, что вы делаете, не сработает.Это часть того, что называется «макро-гигиеной»: вещи, объявленные внутри макросов, не могут «просочиться» в окружающую область.

Обычный обходной путь для проблемы, с которой вы сталкиваетесь, - это передать имяидентификатор в макрос в качестве другого аргумента:

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

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

Это будет работать, потому что присвоение имени x помещает его в область действия вызывающей стороны, даже если объявление находится внутри макроса.

Возможно, выобратите внимание, что замыкание является своего рода ненужным, по крайней мере, в этом примере - вы можете просто передать 5 + x как выражение в макрос и развернуть его в строке.

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

Вы называете этот макрос как atest!(x, 5 + x), что немного похоже на собственное закрытие.Это может дать вам идею написать atest!(|x| 5 + x) вместо этого.И это также будет работать, с переменной, охватывающей замыкание:

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

Ссылки

0 голосов
/ 13 мая 2018

Возможно ли сделать эту работу?Насколько я понимаю, макросы раскрываются перед компиляцией?

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

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

...