В компьютерном программировании , переменная затенение происходит , когда переменная объявлена в пределах определенного объема (решение блока, методы или внутреннего класса ) имеет такое же имя , как переменная объявлена во внешней области видимости. На уровне идентификаторов (имен, а не переменных) это называется маскированием имени . Считается, что эта внешняя переменная затеняется внутренней переменной, а внутренний идентификатор маскирует внешний идентификатор. Это может привести к путанице, поскольку может быть неясно, к какой переменной относятся последующие использования имени скрытой переменной, что зависит от правил разрешения имен языка.
Одним из первых языков, в которых было введено затенение переменных, был ALGOL , в котором впервые были введены блоки для определения областей видимости. Это также было разрешено многими производными языками программирования, включая C , C ++ и Java .
Язык C # нарушает эту традицию, разрешая затенение переменных между внутренним и внешним классами, а также между методом и содержащим его классом, но не между блоком if и содержащим его методом или между операторами case в блоке switch .
Некоторые языки допускают затенение переменных в большем количестве случаев, чем другие. Например, Kotlin позволяет внутренней переменной в функции затенять переданный аргумент, а переменная во внутреннем блоке затенять другую во внешнем блоке, в то время как Java не позволяет этого. Оба языка позволяют переданному аргументу функции / методу затенять поле класса. [1]
Некоторые языки полностью запрещают затенение переменных, например CoffeeScript . [2]
Пример
Lua
Следующий код Lua предоставляет пример затенения переменных в нескольких блоках.
v = 1 - глобальная переменнаяdo local v = v + 1 - новый локальный, который затеняет глобальный v print ( v ) - печатает 2 do local v = v * 2 - другой локальный, который затеняет внешний локальный v print ( v ) - печатает 4 end print ( v ) - печатает 2 концаprint ( v ) - печатает 1
Python
Следующий код Python предоставляет еще один пример затенения переменных:
х = 0def external (): x = 1 def inner (): x = 2 print ( "inner:" , x ) inner () print ( "внешний:" , x )external () print ( "глобальный:" , x )# выводит # внутренний: 2 # внешний: 1 # глобальный: 0
Поскольку в Python нет объявления переменных, а только присваивается переменная, ключевое слово, nonlocal
введенное в Python 3, используется для предотвращения затенения переменных и присвоения нелокальным переменным:
х = 0def external (): x = 1 def inner (): нелокальный x x = 2 print ( "inner:" , x ) inner () print ( "внешний:" , x )external () print ( "глобальный:" , x )# выводит # внутренний: 2 # внешний: 2 # глобальный: 0
Ключевое слово global
используется, чтобы избежать затенения переменных и присвоить глобальным переменным:
х = 0def external (): x = 1 def inner (): global x x = 2 print ( "inner:" , x ) inner () print ( "внешний:" , x )external () print ( "глобальный:" , x )# выводит # внутренний: 2 # внешний: 1 # глобальный: 2
Ржавчина
fn main () { пусть x = 0 ; { пусть x = 1 ; println! ( "Внутренний x: {}" , x ); // выводит 1 } println! ( "Внешний x: {}" , x ); // выводит 0 // Shadow let x = "Rust" ; println! ( "Внешний x: {}" , x ); // выводит 'Rust' } // # Внутренний x: 1 // # Внешний x: 0 // # Внешний x: Rust
C ++
#include int main () { int x = 42 ; int sum = 0 ; для ( int я = 0 ; я < 10 ; я ++ ) { int х = я ; std :: cout << "x:" << x << '\ n' ; // выводит значения i от 0 до 9 sum + = x ; } std :: cout << "сумма:" << сумма << '\ n' ; std :: cout << "x:" << x << '\ n' ; // выводит 42 возврат 0 ; }
Ява
публичный класс Shadow { частный int myIntVar = 0 ; public void shadowTheVar () { // Поскольку он имеет то же имя, что и поле экземпляра вышеупомянутого объекта, он затеняет // над полем внутри этого метода. int myIntVar = 5 ; // Если мы просто обратимся к 'myIntVar', будет найден один из этого метода // (затенение второго с тем же именем) System . из . println ( myIntVar ); // выводит 5 // Если мы хотим сослаться на затененный myIntVar из этого класса, нам нужно // обратиться к нему следующим образом: System . из . println ( this . myIntVar ); // выводит 0 } public static void main ( String [] args ) { новая тень ( "красный" ). shadowTheVar (); } }
JavaScript
Введение в ECMAScript 6 `let` и` const` с блочной областью видимости допускает затенение переменных.
функция myFunc () { let my_var = 'test' ; if ( true ) { let my_var = 'новый тест' ; консоль . журнал ( my_var ); // новый тест } console . журнал ( my_var ); // тест } myFunc ();