第一版是针对 Lua 5.0 编写的。虽然对于后续版本来说仍然非常相关,但还是有一些区别。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目。
![]() |
用 Lua 编程 | ![]() |
| 第二部分。表和对象 第 13 章。元表和元方法 |
__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)。
| 版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 | ![]() |