この第1版は、Lua 5.0 向けに記述されました。後続バージョンでも依然として多くが関連していますが、いくつかの相違があります。
第4版は Lua 5.3 を対象としており、Amazon や他の書店で購入できます。
本の購入によって、Lua プロジェクトのサポートに協力できます。


14.3 – グローバル以外の環境

環境に関する問題の1つは、それがグローバルであることです。そこで加えた変更は、プログラムのあらゆる部分に影響します。たとえば、グローバルアクセスを制御するためメタテーブルをインストールする場合、プログラム全体がそのガイドラインに従う必要があります。グローバル変数を使用したライブラリを使用したいのに、それを宣言していない場合は、運が悪いことになります。

Lua 5.0 では、各関数が独自の環境を持てるようにすることで、この問題が軽減されています。最初は奇妙に聞こえるかもしれませんが、結局のところ、グローバル変数のテーブルの目標はグローバルであることです。ただし、セクション15.4 では、この機能によりグローバル値をどこにでも利用できる状態にしたまま、いくつかの興味深い構成が可能になることがわかります。

setfenv 関数(関数環境の設定)を使用して、関数の環境を変更できます。それには関数と新しい環境が渡されます。関数自体ではなく、数値を渡すこともできます。つまり、指定されたスタックレベルでアクティブな関数です。数値1は現在の関数を示し、数値2は現在の関数を呼び出している関数(呼び出し元の環境を変更する補助関数を記述するのに便利です)などを示します。

setfenv を使用する単純な最初の試みは、見事に失敗します。コード

    a = 1   -- create a global variable
    -- change current environment to a new empty table
    setfenv(1, {})
    print(a)
は次のように結果します。
    stdin:5: attempt to call global `print' (a nil value)
(そのコードは単一のチャンクで実行する必要があります。インタラクティブモードで1行ずつ入力した場合、各行は別の関数になり、setfenv への呼び出しは自分自身の行にしか影響しません。)環境を変更すると、すべてのグローバルアクセスでこの新しいテーブルが使用されます。それが空の場合、_G を含むすべてのグローバル変数が失われます。したがって、まず print などの古い環境などのように、いくつかの有用な値でそれを設定する必要があります。
    a = 1   -- create a global variable
    -- change current environment
    setfenv(1, {_G = _G})
    _G.print(a)      --> nil
    _G.print(_G.a)   --> 1
これで、「グローバル」_G にアクセスすると、その値は古い環境になり、その中でフィールド print を見つけることができます。

継承を使用しても、新しい環境を設定できます。

    a = 1
    local newgt = {}        -- create new environment
    setmetatable(newgt, {__index = _G})
    setfenv(1, newgt)    -- set it
    print(a)          --> 1
このコードでは、新しい環境は printa の両方を古い環境から継承します。それにもかかわらず、割り当ては新しいテーブルに行きます。_G を介してそれらを変更することはできますが、本当にグローバルな変数を誤って変更する危険はありません。
    -- continuing previous code
    a = 10
    print(a)      --> 10
    print(_G.a)   --> 1
    _G.a = 20
    print(_G.a)   --> 20

新しい関数を作成すると、作成する関数からその環境を継承します。したがって、チャンクが独自の環境を変更した場合、その後に定義するすべての関数は、同じ環境を共有します。これは、次の章で説明するように、名前空間を作成するための便利なメカニズムです。