这将证明其速度非常慢并且内存效率低下。不管怎样,你是对的:代理和句柄__index
and __newindex
您喜欢的元方法。话虽如此,您还需要以某种方式跟踪代理的状态。
您可以尝试使用一些闭包和上值来隐藏它,但简单的方法是将信息直接存储在代理表中:
function make_tracker (o, name)
local mt = {}
mt.__index = function (proxy, key)
local path = {unpack(rawget(proxy, "__path"))} -- Stupid shallow copy
local object = rawget(proxy, "__to")
table.insert(path, key)
if type(object[key]) == "table" then
return setmetatable({__to = object[key], __path = path}, mt)
else
return table.concat(path, ".") .. " = " .. tostring(object[key])
end
end
return setmetatable({__to = o, __path = {name}}, mt)
end
__to
字段指示代理应该指向什么__path
是为了覆盖我们迄今为止所侵入的领域吗?它进行浅复制,以便可以将子代理与局部变量一起使用。name
参数用于初始化第一个表的名称,因为您根本不知道这一点。你像这样使用它:
local tObjects = make_tracker(Objects, "Objects")
local subproxy = tObjects.Panel.objects.Window
print(subproxy.objects.label.text)
print(tObjects.Panel.objects.label.text)
print(subproxy.x)
-- prints:
-- Objects.Panel.objects.Window.objects.label.text = lorem ipsum dorem
-- Objects.Panel.objects.label.text = header
-- Objects.Panel.objects.Window.x = 400
当然,我怀疑将路径附加到原始值是您想要的。修改内部else
block:
return table.concat(path, ".") .. " = " .. tostring(object[key])
根据您的需要,例如:
register_tracked_path(table.concat(path, "."))
return object[key]
如果你想处理值的修改,你需要用类似的方法扩展元表__newindex
.