この初版は、Lua 5.0 のために書かれました。以後のバージョンでも大部分は関連性がありますが、いくつかの違いがあります。
第 4 版は Lua 5.3 を対象にしており、Amazon や他の書店で入手可能です。
この本を購入することも、Lua プロジェクトをサポートすることに役立ちます。


13.4.4 - テーブルへのアクセスの追跡

__index__newindex の両方は、インデックスがテーブルにない場合にのみ関連します。テーブルへのすべてのアクセスを取得する唯一の方法は、テーブルを空のままにしておくことです。したがって、テーブルへのすべてのアクセスを監視したい場合は、実際のテーブルのプロキシを作成する必要があります。このプロキシは、すべてのアクセスを追跡し、元のテーブルにリダイレクトする適切な __index__newindex メタメソッドを持つ空のテーブルです。t が追跡したい元のテーブルであるとします。次のように記述できます。

    t = {}   -- original table (created somewhere)
    
    -- keep a private access to original table
    local _t = t
    
    -- create proxy
    t = {}
    
    -- create metatable
    local mt = {
      __index = function (t,k)
        print("*access to element " .. tostring(k))
        return _t[k]   -- access the original table
      end,
    
      __newindex = function (t,k,v)
        print("*update of element " .. tostring(k) ..
                             " to " .. tostring(v))
        _t[k] = v   -- update original table
      end
    }
    setmetatable(t, mt)
このコードは t へのあらゆるアクセスを追跡します
    > t[2] = 'hello'
    *update of element 2 to hello
    > print(t[2])
    *access to element 2
    hello
(残念ながら、このスキームではテーブルをトラバースできないことに注意してください。pairs 関数は元のテーブルではなく、プロキシに対して動作します。)

複数のテーブルを監視する場合、それぞれに異なるメタテーブルは必要ありません。代わりに、なんらかの方法で各プロキシを元のテーブルに関連付け、すべてのプロキシに共通のメタテーブルを共有できます。プロキシをテーブルに関連付ける簡単な方法は、他の手段にこのフィールドが使用されないように自信があれば、元のテーブルをプロキシのフィールドに保持することです。これを保証する簡単な方法は、誰もアクセスできない秘密鍵を作成することです。これらのアイデアをまとめると、次のコードになります

    -- create private index
    local index = {}
    
    -- create metatable
    local mt = {
      __index = function (t,k)
        print("*access to element " .. tostring(k))
        return t[index][k]   -- access the original table
      end,
    
      __newindex = function (t,k,v)
        print("*update of element " .. tostring(k) ..
                             " to " .. tostring(v))
        t[index][k] = v   -- update original table
      end
    }
    
    function track (t)
      local proxy = {}
      proxy[index] = t
      setmetatable(proxy, mt)
      return proxy
    end
これで、テーブル t を監視したい場合は、t = track(t) とするだけで済みます。