この初版は Lua 5.0 向けに書かれました。後期のバージョンでもまだほとんど関連がありますが、いくつかの違いがあります。
第 4 版は Lua 5.3 をターゲットにしており、Amazon や他の書店で入手できます。
本を購入することで、Lua プロジェクトをサポートすることにもつながります。


14.1 – 動的変数名によるグローバル変数へのアクセス

通常は、代入でグローバル変数の取得と設定ができます。しかし、メタプログラミングの一種が必要になることがよくあります。たとえば、別の変数に格納されている名前のグローバル変数を操作したり、何らかの方法で実行時に計算したりする必要がある場合などです。この変数の値を取得するために、多くのプログラマーは次のようなコードを書くことに誘惑されます。

    loadstring("value = " .. varname)()
または
    value = loadstring("return " .. varname)()
たとえば、varnamex の場合、連結の結果は "return x"(または最初の形式の場合は "value = x")になります。実行すると、目的の結果が得られます。しかし、そのようなコードには新しいチャンクの作成とコンパイル、および多数の追加作業が含まれます。同じ効果は、次のようなコードで実現できます。これは、前のコードよりも桁違いに効率的です。
    value = _G[varname]
環境は通常のテーブルなので、目的のキー(変数名)でインデックスを付けるだけで済みます。

同様に、_G[varname] = value と記述することで、動的に計算された名前のグローバル変数に代入できます。ただし、注意が必要です。これらの関数に少し興奮したプログラマーの中には、_G["a"] = _G["var1"] のようなコードを書く人もいますが、これは a = var1 と記述する複雑な方法にすぎません。



前述の問題の一般化は、"io.read""a.b.c.d" などの動的名前のフィールドを許可することです。この問題は、_G から開始され、フィールドごとに進化するループで解決します。

    function getfield (f)
      local v = _G    -- start with the table of globals
      for w in string.gfind(f, "[%w_]+") do
        v = v[w]
      end
      return v
    end
f のすべての単語(「単語」は英数字と下線文字のシーケンスの 1 つ以上)を反復処理するために、string ライブラリからの gfind に依存します。

フィールドを設定するための対応する関数は、少し複雑です。次のような代入は

    a.b.c.d.e = v
次の場合とまったく同じです。
    local temp = a.b.c.d
    temp.e = v
つまり、最後の名前まで取得する必要があります。最後のフィールドは別途処理しなければなりません。新しい setfield 関数は、存在しない場合にパスの途中に中間テーブルも作成します。
    function setfield (f, v)
      local t = _G    -- start with the table of globals
      for w, d in string.gfind(f, "([%w_]+)(.?)") do
        if d == "." then      -- not last field?
          t[w] = t[w] or {}   -- create table if absent
          t = t[w]            -- get the table
        else                  -- last field
          t[w] = v            -- do the assignment
        end
      end
    end
この新しいパターンは、変数 w にフィールド名と、続くオプションのドットを d にキャプチャします。フィールド名の後にドットが続かない場合は、それは最後の名前です(パターンマッチングについては、第 20 章 で詳しく説明します)。

前の関数を使用すると、コールがあります。

    setfield("t.x.y", 10)
グローバルテーブル t、別のテーブル t.x を作成し、10 を t.x.y に代入します。
    print(t.x.y)     --> 10
    print(getfield("t.x.y"))   --> 10