当访问一个 table 或者更新 table 中的某个元素时,lua 首先会在 table 查找是否存在该元素,如果没有,就会查找 table 是否存在 index(访问) 或者 newindex(更新) 原方法。以访问为例,首先在 table 中查找某个字段,如果不存在,解释器会去查找 index 这个原方法,如果仍然没有,返回 nil。所以说,index 和 __newindex 是在 table 中没有所需访问的 index 时才发挥作用的。

根据上面这种思路,如果我们想跟踪一个 table 的操作行为,那么需要一个空表,每次对这个空表操作的时候,就会使用 index 或者 newindex 这些元方法,在元方法中对原始 table 进行访问和操作,并打印跟踪信息。而之前创建的那个空表,就是代理。

---------------------------------------------
print "跟踪单个表"

local _t = {}

local mt = {
__newindex = function(t, name, value)
print("__newindex", name, value)
–rawset(_t, name, value) --原始访问 不访问原表
_t[name] = value
end,

__index = function(t, name)
    print("__index", name, value)
    --return rawget(_t, name) --原始访问 不访问原表
    return _t[name]
end

}

–a.__index = a
local a = {}
setmetatable(a, mt)

a.x = 1
print(a.x)


print "跟踪多个表"

local index = {} – 创建私有索引,即原表在代理表中特殊字段

local mt = {
__index = function (t, k)
print("__index " … tostring(k))
return t[index][k]
end,
__newindex = function (t, k, v)
print("__newindex " … tostring(k) … " to " … tostring(v))
t[index][k] = v
end
}

function track (t)
local proxy = {}
proxy[index] = t
setmetatable(proxy, mt)
return proxy
end

local ori_table = {} --在其他地方创建的原表,对他进行跟踪
local _o = track(ori_table)

_o[2] = "lua"
print(_o[2])