第一版是為 Lua 5.0 編寫的。雖然在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 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)