コンピュータ プログラミングでは、特定のスコープ(決定ブロック、メソッド、または内部クラス)内で宣言された変数が、外部スコープで宣言された変数と同じ名前を持つ場合に、変数のシャドウイングが発生します。識別子(変数ではなく名前)のレベルでは、これは名前のマスキングと呼ばれます。この外部変数は内部変数によってシャドウイングされると言われ、内部識別子は外部識別子をマスクすると言われます。これにより、シャドウイングされた変数名がその後に使用されるときにどの変数を参照するかが不明瞭になる可能性があり、これは言語の 名前解決ルールによって異なります。
変数シャドウイングを導入した最初の言語の 1 つはALGOLで、スコープを確立するためのブロックを初めて導入しました。これは、 C、C++、Javaなどの多くの派生プログラミング言語でも許可されています。
C #言語はこの伝統を破り、内部クラスと外部クラス間、メソッドとその包含クラス間で変数のシャドウイングを許可しますが、if ブロックとその包含メソッド間、またはswitchブロック内の case ステートメント間では許可しません。
言語によっては、他の言語よりも変数のシャドウイングが可能なケースが多い。例えばKotlinでは、関数内の内部変数が渡された引数をシャドウイングしたり、内部ブロック内の変数が外部ブロック内の別の変数をシャドウイングしたりできるが、Javaではこれらは許可されていない。どちらの言語でも、関数/メソッドに渡された引数がクラスフィールドをシャドウイングできる。[1]
CoffeeScript [2]やV (Vlang) [3]などの一部の言語では変数のシャドウイングが完全に禁止されています。
例
ルア
次の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コードは、変数シャドウイングの別の例を示しています。
x = 0
外側の定義():
x = 1
def inner ():
x = 2
print ( "inner:" , x )
内側()
print ( "外側:" , x )
外側()
print ( "global:" , x )
# 印刷
# 内部: 2
# 外部: 1
# グローバル: 0
nonlocalPython では変数の宣言はなく、変数の割り当てのみであるため、変数のシャドウイングを回避し、非ローカル変数に割り当てるために、Python 3 で導入された
キーワードが使用されます。
x = 0
外側の定義():
x = 1
def inner ():
非ローカル x
x = 2
print ( "inner:" , x )
内側()
print ( "外側:" , x )
外側()
print ( "global:" , x )
# 印刷
# 内部: 2
# 外部: 2
# グローバル: 0
キーワードはglobal変数のシャドウイングを回避し、グローバル変数に割り当てるために使用されます。
x = 0
外側の定義():
x = 1
def inner ():
global x
x = 2
print ( "inner:" , x )
内側()
print ( "外側:" , x )
外側()
print ( "global:" , x )
# 印刷
# 内部: 2
# 外部: 1
# グローバル: 2
さび
fn main () { let x = 0 ; { // Shadow let x = 1 ; println! ( "Inner x: {}" , x ); // 1 が出力されます} println! ( "Outer x: {}" , x ); // 0 が出力されますlet x = "Rust" ; println! ( "Outer x: {}" , x ); // 'Rust' が出力されます}
//# 内側の x: 1
//# 外側の x: 0
//# 外側の x: Rust
C++
#include <iostream>
int main () { int x = 42 ; int合計= 0 ;
for ( int i = 0 ; i < 10 ; i ++ ) { int x = i ; std :: cout << "x: " << x << '\n' ; // 0 から 9 までの i の値を出力しますsum += x ; }
std :: cout << "sum: " << sum << '\n' ; // 45 を出力std :: cout << "x: " << x << '\n' ; // 42 を出力
0 を返す; }
ジャワ
パブリッククラスShadow {プライベートint myIntVar = 0 ;
public void shadowTheVar () { // 上記のオブジェクト インスタンス フィールドと同じ名前なので、このメソッド内で上記のフィールドをシャドウします。int myIntVar = 5 ;
// 単に 'myIntVar' を参照すると、このメソッドの 1 つが見つかります
// (同じ名前の 2 番目のメソッドをシャドウイングします) System . out . println ( myIntVar ); // 5 を出力します
// このクラスからシャドウされた myIntVar を参照する場合は
、次のように参照する必要があります: System . out . println ( this . myIntVar ); // 0 を出力します}
パブリック静的void main ( String [] args ){新しいShadow () .shadowTheVar (); } }
JavaScript
ECMAScript 6 では、ブロック スコープの と が
導入されlet、変数のシャドウイングが可能になります。const
function myFunc () { let my_var = ' test' ; if ( true ) { let my_var = ' new test' ; console.log ( my_var ) ; // 新しいテスト} console.log ( my_var ); // テスト} myFunc ( );
