2.2 – スコープ、変数、環境

変数名は、コード上のその位置で有効な宣言に従い、グローバル変数またはローカル変数を参照する。(ここでの議論では、関数の仮引数はローカル変数と同等である。)

すべてのチャンクは、すべての自由名をグローバル変数として宣言する暗黙の宣言global *で始まる。次の例に示すように、この冒頭の宣言は、別のglobal宣言のスコープ内では無効になる。

     X = 1       -- Ok, global by default
     do
       global Y  -- voids the implicit initial declaration
       Y = 1     -- Ok, Y declared as global
       X = 1     -- ERROR, X not declared
     end
     X = 2       -- Ok, global by default again

したがって、どのglobal宣言の外側でも、Luaはデフォルトでグローバルとして動作する。global宣言の内側ではデフォルトがなく、すべての変数を宣言しなければならない。

Luaはレキシカルスコープを持つ言語である。変数宣言のスコープは、宣言直後の最初の文から始まり、その宣言を含む最も内側のブロックにある最後の非void文まで続く。(Void文とは、ラベルと空文である。)

ある宣言は、その宣言位置で有効な同名の宣言を隠蔽する。この隠蔽の内側では、その名前に対する外側の宣言はすべて無効となる。次の例を参照すること。

     global print, x
     x = 10                -- global variable
     do                    -- new block
       local x = x         -- new 'x', with value 10
       print(x)            --> 10
       x = x+1
       do                  -- another block
         local x = x+1     -- another 'x'
         print(x)          --> 12
       end
       print(x)            --> 11
     end
     print(x)              --> 10  (the global one)

local x = xのような宣言では、宣言中の新しいxはまだスコープ内にないため、右辺のxは外側の変数を参照することに注意すること。

レキシカルスコープの規則により、ローカル変数のスコープ内で定義された関数は、そのローカル変数へ自由にアクセスできる。内側の関数が使用するローカル変数は、その内側の関数ではアップバリュー(または外部ローカル変数、単に外部変数)と呼ばれる。

local文を実行するたびに、新しいローカル変数が定義されることに注意すること。次の例を考える。

     a = {}
     local x = 20
     for i = 1, 10 do
       local y = 0
       a[i] = function () y = y + 1; return x + y end
     end

このループは、10個のクロージャ(すなわち無名関数の10個のインスタンス)を作成する。これらのクロージャはそれぞれ異なるy変数を使用する一方、すべてが同じxを共有する。

§3.2および§3.3.3でさらに説明するように、グローバル変数varへの参照はすべて構文的に_ENV.varへ変換される。さらに、各チャンクは_ENVという名前の外部ローカル変数のスコープ内でコンパイルされるため(§3.3.2を参照)、_ENV自体がチャンク内の自由名になることはない。

この外部_ENV変数と自由名の変換が存在するにもかかわらず、_ENVは通常の名前である。特に、この名前を持つ新しい変数や引数を定義できる。(ただし、_ENVをグローバル変数として定義するべきではない。定義すると_ENV.var_ENV._ENV.varへ変換され、以下同様に無限ループとなる。)グローバル変数名への各参照は、プログラム上のその位置で見える_ENVを使用する。

_ENVの値として使用されるテーブルは、すべて環境と呼ばれる。

Luaは、グローバル環境と呼ばれる特別な環境を保持している。この値はCレジストリ内の特別なインデックスに保持される(§4.3を参照)。Luaでは、グローバル変数_Gが同じ値で初期化される。(_Gが内部で使用されることはないため、その値の変更は自分のコードだけに影響する。)

Luaがチャンクを読み込むとき、その_ENV変数のデフォルト値はグローバル環境である(loadを参照)。そのため、デフォルトでは、Luaコード内のグローバル変数はグローバル環境のエントリーを参照し、従来のグローバル変数として動作する。さらに、すべての標準ライブラリがグローバル環境へ読み込まれ、そこにある一部の関数はその環境に対して動作する。load(またはloadfile)を使用すると、異なる環境でチャンクを読み込める。(Cでは、チャンクを読み込んだ後、その最初のアップバリューの値を変更する必要がある。lua_setupvalueを参照。)