获取所需值的完整路径

如何在表中获取所需值的完整路径?我想通过代理表跟踪另一个表中的更改。

我知道我需要使用元表和__index。但是我还没有能够想出一个跟踪器。

示例表结构:

Objects = {
Panel = { layer = 1, x = 600, y = 328, w = 331, h = 491;
    objects = {
        label = { layer = 1, x = 0, y = 0, text = 'header' };
        Window = { layer = 2, x = 400, y = 100, w = 100, h = 100;
            objects = {
                label = { layer = 1, x = 0, y = 0, text = 'lorem ipsum dorem' };
            };
        };
    };
};
};

路径:Objects.Panel.objects.Window.objects.label.text

我尝试为每个表创建一个元表,并收集对__index的每次调用的结果到表中,以大致了解检索或更改的哪个键和值,并将这些值与其他表同步。

点赞
用户4567755
用户4567755

这将证明其自身效率极慢且不经济。无论如何,你的方向是正确的:代理和处理__index__newindex元方法以适应你的需要。话虽如此,你还需要以某种方式跟踪代理的状态。

你可以尝试使用一些闭包和上值来隐藏它,但简单的方法是直接在代理表中存储信息:

function make_tracker (o, name)
  local mt = {}
  mt.__index = function (proxy, key)
    local path = {unpack(rawget(proxy, "__path"))} -- 愚蠢的浅层复制
    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)

-- 输出:
-- Objects.Panel.objects.Window.objects.label.text = lorem ipsum dorem
-- Objects.Panel.objects.label.text = header
-- Objects.Panel.objects.Window.x = 400

当然,我怀疑将路径附加到原始值中是否符合你的意愿。根据需要修改else块的内部:

return table.concat(path, ".") .. " = " .. tostring(object[key])

例如:

register_tracked_path(table.concat(path, "."))
return object[key]

如果你想处理值的修改,你需要使用类似的__newindex扩展元表。

2020-08-25 14:16:34