Shadowing — это возможность многократно объявлять переменную с одним и тем же именем в одной области видимости, при этом новая переменная "затеняет" предыдущую. В языках без shadowing (C, C++) повторное определение переменной приводит к ошибке или неопределённому поведению. Rust разрешает shadowing, и при этом каждая переменная — независимый объект с новым типом или значением. Это удобно при пошаговых преобразованиях значения — например, строку сразу превращать в число, не придумывая новые имена.
Проблема: с одной стороны — улучшение читаемости, предотвращение раздувания имён переменных; с другой — затруднённый дебаг, если случайно "затенить" переменную в сложном блоке и получить неожиданный результат.
Решение: Shadowing используется только там, где это действительно облегчает преобразование и не ухудшает читаемость. Каждое "let var = ...;" создаёт новую переменную, старая остаётся неизменной вне блока объявления.
Пример кода:
fn example() { let x = "42"; let x = x.parse::<i32>().unwrap(); println!("x: {}", x); // x: 42 }
Ключевые особенности:
Может ли shadowing изменять мутабельность переменной?
Да, можно "затенить" немутируемую переменную мутируемой и наоборот:
let x = 5; let mut x = x; x += 1;
Означает ли shadowing, что предыдущая переменная была уничтожена?
Нет, значения предыдущей переменной живут до конца блока, где были объявлены, но становятся недоступны по имени.
Можно ли использовать shadowing внутри цикла или внутри вложенных блоков?
Да, каждая область видимости (скоуп) позволяет объявлять переменные с одними и теми же именами, и это разные переменные.
В функции есть let result = expr1; ... let result = expr2;, где типы отличаются.
Плюсы:
Минусы:
Используется shadowing только для смены типа: сначала парсится строка, затем — присваивание числового.
Плюсы:
Минусы: