В Rust область видимости переменной ограничена блоком (лестничной фигурной скобкой {}). Объявление новой переменной с тем же именем, что и существующая в текущей или внешней области, называется shadowing ("затенение"). Shadowing позволяет изменять тип и значение переменной, не нарушая концепцию иммутабельности.
Пример:
let x = 5; // x: i32 = 5 let x = x + 1; // x: i32 = 6 (затеняет старую x) let x = "hello"; // x: &str = "hello" (изменился тип)
Shadowing не влияет на производительность (это исключительно синтаксическая конструкция, компилируется в разные переменные на уровне LLVM IR), но может значительно ухудшить читаемость и сопровождение кода, увеличивая риск логических ошибок.
Вопрос: Приводит ли shadowing переменной к очистке ресурсов, если предыдущая переменная имела собственник на память (например, String)?
Часто отвечают: Нет, ведь переменная просто "переопределяется".
Правильный ответ: Да, когда переменная затеняется, старое значение выходит из области видимости и, если оно владело ресурсом, вызывается Drop. Это обеспечивает корректное освобождение памяти.
Пример:
let s = String::from("abc"); let s = 5; // String освобождается здесь (вызван Drop)
История
Молодой разработчик использовал shadowing для одной из структур с открытым файловым дескриптором и, затенив переменную ранее, чем планировалось, случайно закрыл файл до окончания работы. Это привело к потере данных в некоторых случаях.
История
В одном исследовательском проекте shadowing применялся для переменных одного уровня вложенности, из-за чего разработчики часто путались и обращались к "старому" значению переменной, думая, что оно актуально.
История
В крупном серверном приложении неявное shadowing поля структуры и переменной внутри метода вызвало неочевидную ошибку, когда поле не изменялось, а менялась новая локальная переменная с тем же именем. Ошибка была обнаружена после долгого поиска причин неправильного поведения системы.