首页 > 代码库 > chapter 13_4 跟踪table的访问
chapter 13_4 跟踪table的访问
__index和__newindex都是在table中没有所需访问的index时才发挥作用。
因此,只有将一个table保持为空,才有可能捕捉到所有对它的访问。为了监视一个table的所有访问,就应该为真正的table创建一个代理。
这个代理就是一个空的table,其中__index和__newindex元方法可用于跟踪所有的访问,并将访问重定向到原来的table上。
假设我们要跟踪table t 的访问,可以这样做:
t = {} --original table, 在其他地方创建的local _t = t --保持对原table的一个私有访问t = {} --创建一个代理local mt = { __index = function (t,k) print("*access to elemet " .. tostring(k)) return _t[k] --访问原table中的k end __newindex = function(t,k,v) print("*update of element" .. tostring(k) .. " to " .. tostring(v)) _t[k] = v --更新原table的值 end}setmetatable(t,mt) --将mt设置为 t 的元表
这段代码跟踪了所有对 table t 的访问:
t[2] = "hello" -- *update of element 2 to helloprint(t[2]) --> hello -- *access to element 2
但是上面的例子有一个问题,就是无法遍历原来的table。函数pairs只能操作代理table,而无法访问原来的table。
可以通过定义__pairs去遍历:
mt.__pairs = function() return function(_,k) return next(_t,k) endend
如果想要同时监视几个table,无须为每个table创建不同的元表。相反,只要以某种形式将每个代理与其原table关联起来,
并且所有代理都共享一个公共的元表。这个问题与前一节所讨论的将table与其默认值相关联的问题类似。
例如将原来table保存在代理table的一个特殊字段中,如下:
local index = {} --创建私有索引local mt = { --创建元表 __index = function(t,k) print("*access to element " .. tostring(k) return t[index][k] --访问原来的table end __newindex = function(t,k,v) print("*update of element " .. tostring(k) .. " to " .. tostring(v)) t[index][k] = v --更新原来的table end __pairs = function(t) return function(t,k) return next(t[index],k) end , t end}function track(t) local proxy= {} proxy[index] = t setmetatable(proxy,mt) return proxyend
现在,若要监视table t ,唯一要做的就是执行:
t = track(t)
只读的table
通过代理的概念,可以很容易地就实现出只读的table,只需跟踪所有对table的跟新操作,并引发一个错误就可以了。
由于无须跟踪查询访问,所以对于__index元方法可以直接使用原table来代替函数。这也更简单,并且在重定向所有查询到原table时效率也更高。
不过,这种做法要求为每个只读代理创建一个新的元表,其中__index指向原来的table。
function readOnly(t) local proxy = {} local mt = { __index =t , __newindex = function(t,k,v) error("*attempt to update a read-only table",2) end } setmetatable(proxy,mt) return proxyend
下面是一个使用的示例,创建了一个表示星期的只读table:
days = readOnly{"Sunday","Monday","Tuesday","Thursday","Friday","Saturday"}print(days[1]) -->Sundaydays[2] = "Noday" -- > stdin:1: attempt to update a read-only table
以上内容来自:《Lua程序设计第二版》和《Programming in Lua third edition 》
chapter 13_4 跟踪table的访问