この第1版はLua 5.0用に書かれました。後続のバージョンと依然として大きく関連しますが、いくつかの違いがあります。
第4版はLua 5.3をターゲットにしており、Amazonおよびその他の本屋で入手できます。
この本を購入することで、Luaプロジェクトをサポートすることにもなります。


14.2 - グローバル変数の宣言

Luaのグローバル変数は、宣言する必要がありません。これは小規模なプログラムにとっては便利ですが、大規模なプログラムでは簡単なタイプミスが発見の難しいバグを引き起こす可能性があります。ただし、必要に応じてその動作を変更できます。Luaはグローバル変数を通常のテーブルに保持するため、グローバル変数にアクセスするときにその振る舞いを変更するためにメタテーブルを使用できます。

最初の方法は次のとおりです

    setmetatable(_G, {
      __newindex = function (_, n)
        error("attempt to write to undeclared variable "..n, 2)
      end,
      __index = function (_, n)
        error("attempt to read undeclared variable "..n, 2)
      end,
    })
そのコードの後で、存在しないグローバル変数にアクセスしようとすると、エラーが発生します
    > a = 1
    stdin:1: attempt to write to undeclared variable a

しかし、新しい変数をどのように宣言するのでしょうか?メタメソッドをバイパスする「rawset」を使用して

    function declare (name, initval)
      rawset(_G, name, initval or false)
    end
falseを使ったorは、新しいグローバル変数が常にnilとは異なる値を取得することを保証します。アクセス制御をインストールする前にこの関数を定義する必要があることに注意してください。そうでないとエラーが発生します。結局のところ、新しいグローバル変数「declare」を作成しようとしています。その関数を配置すると、グローバル変数を完全に制御できます
    > a = 1
    stdin:1: attempt to write to undeclared variable a
    > declare"a"
    > a = 1             -- OK

しかし、次に、変数が存在するかどうかをテストするために、単にnilと比較することはできません。それがnilの場合、アクセスによりエラーが発生します。代わりに、メタメソッドを回避する「rawget」を使用します

    if rawget(_G, var) == nil then
      -- `var' is undeclared
      ...
    end

その制御を変更してnil値を持つグローバル変数を許可するのは難しくありません。必要なのは、宣言された変数の名前を保持する補助テーブルだけです。メタメソッドが呼び出されるたびに、そのテーブルで変数が宣言されているかどうかが確認されます。コードは次のようになります

    local declaredNames = {}
    function declare (name, initval)
      rawset(_G, name, initval)
      declaredNames[name] = true
    end
    setmetatable(_G, {
      __newindex = function (t, n, v)
        if not declaredNames[n] then
          error("attempt to write to undeclared var. "..n, 2)
        else
          rawset(t, n, v)   -- do the actual set
        end
      end,
      __index = function (_, n)
        if not declaredNames[n] then
          error("attempt to read undeclared var. "..n, 2)
        else
          return nil
        end
      end,
    })

どちらのソリューションにとっても、オーバーヘッドは無視できます。最初のソリューションでは、正常な動作中にメタメソッドが呼び出されることはありません。2番目のソリューションでは、メタメソッドが呼び出される場合がありますが、プログラムがnilを保持する変数にアクセスした場合のみです。