Почему гигиена макросов не предотвращает коллизии между множественными определениями const?
Я думал, что "гигиена" предотвратит столкновения между X
определены в моем макросе m!
но оказалось, что это не так. Что я недопонимаю?
macro_rules! m {
($e:expr) => {
const X: i32 = $e;
}
}
m!(0);
m!(1);
fn main() {
m!(2);
m!(3);
}
Сообщение об ошибке:
<anon>:3:9: 3:27 error: duplicate definition of value `X` [E0428]
<anon>:3 const X: i32 = $e;
^~~~~~~~~~~~~~~~~~
<anon>:8:1: 8:7 note: in this expansion of m! (defined in <anon>)
<anon>:3:9: 3:27 help: see the detailed explanation for E0428
<anon>:3:9: 3:27 note: first definition of value `X` here
<anon>:3 const X: i32 = $e;
^~~~~~~~~~~~~~~~~~
<anon>:7:1: 7:7 note: in this expansion of m! (defined in <anon>)
<anon>:3:9: 3:27 error: duplicate definition of value `X` [E0428]
<anon>:3 const X: i32 = $e;
...snip...
1 ответ
С https://doc.rust-lang.org/book/macros.html:
Это [то есть переименование] верно для привязок let и меток цикла, но не для элементов
https://doc.rust-lang.org/reference.html:
Предмет является компонентом ящика. Элементы организованы внутри ящика с помощью вложенного набора модулей. Каждый ящик имеет один "самый внешний" анонимный модуль; все остальные элементы внутри ящика имеют пути в дереве модулей ящика.
Элементы полностью определяются во время компиляции, обычно остаются фиксированными во время выполнения и могут находиться в постоянной памяти.
Есть несколько видов предметов:
- внешние объявления
- использовать объявления
- модули
- функции
- определения типов
- Структуры
- перечисления
- постоянные предметы
- статические предметы
- черты
- реализации
Это имеет смысл: если вы вводите элемент в макрос, вы, вероятно, хотите фактически использовать его из других элементов / модулей / ящиков (и, следовательно, вне макроса), но не сможете, если не знаете его имени, поэтому компилятор не может переименовать его.