Ответ Питера объясняет, почему то, что вы делаете, не сработает.Это часть того, что называется «макро-гигиеной»: вещи, объявленные внутри макросов, не могут «просочиться» в окружающую область.
Обычный обходной путь для проблемы, с которой вы сталкиваетесь, - это передать имяидентификатор в макрос в качестве другого аргумента:
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))
};
}
Ссылки