LUA-创建元表,使每个子表再次成为一个元表

  • 本文关键字:一个 创建 LUA- lua metatable
  • 更新时间 :
  • 英文 :


但这肯定会让人感到困惑。

我对LUA还是个新手,有一件事我还没怎么做,那就是跖骨。

我需要找到一种方法来创建一个元表,该表运行一个编辑值的函数。如果我留在";一级";,所以第一个索引。然后我可以简单地使用__newindex来运行它。但我要做的是,每当任何值发生变化时,都要运行该函数。

这将需要某种方式来设置元表内的任何表,使其再次成为运行与"表"相同功能的元表;主";元表

在我的用例中;保存";功能:

function MySaveFunction(tbl)
FileSave(my_settings_path, tbl)
end
MyTable = setmetatable()
MyTable.Value = value --> run MySaveFunction(MyTable.Value)
MyTable.SubTable = {} --> run setmetatable() on SubTable
MyTable.SubTable.Value = value --> run MySaveFunction(MyTable.SubTable.Value)
MyTable.SubTable.SubSubTable = {} --> run setmetatable() on SubSubTable
MyTable.SubTable.SubSubTable.Value = value --> run MySaveFunction(MyTable.SubTable.SubSubTable.Value)
MyTable.SubTable.SubSubSubTable = {} --> run setmetatable() on SubSubSubTable
MyTable.SubTable.SubSubSubTable.Value = value --> run MySaveFunction(MyTable.SubTable.SubSubSubTable.Value)

希望有人能帮助我<

首先要注意的是,__newindex__index元方法只有在处理目标表中的nil值时才会触发。如果您想跟踪每一个更改,就不能只使用__newindex,因为一旦您编写了一个值,后续调用就不会有任何作用。相反,您需要使用代理表。

另一个需要考虑的重要事项是跟踪访问成员的路径。

最后,但同样重要的是,在实现处理程序时,您需要记住使用原始访问函数,例如rawget。否则,您可能会遇到堆栈溢出或其他奇怪的行为。

让我们用一个琐碎的例子来说明这些问题:

local mt = {}
function mt.__newindex (t, key, value)
if type(value) == "table" then
rawset(t, key, setmetatable(value, mt)) -- Set the metatable for nested table
-- Using `t[key] = setmetatable(value, mt)` here would cause an overflow.
else
print(t, key, "=", value) -- We expect to see output in stdout for each write
rawset(t, key, value)
end
end
local root = setmetatable({}, mt)
root.first = 1                   -- table: 0xa40c30 first   =   1
root.second = 2                  -- table: 0xa40c30 second  =   2
root.nested_table = {}           -- /nothing/
root.nested_table.another = 4    -- table: 0xa403a0 another =   4
root.first = 5                   -- /nothing/

现在,我们需要处理它们。让我们从创建代理表的方法开始:

local
function make_proxy (data)
local proxy = {}
local metatable = {
__index = function (_, key) return rawget(data, key) end,
__newindex = function (_, key, value)
if type(value) == "table" then
rawset(data, key, make_proxy(value))
else
print(data, key, "=", value) -- Or your save function here!
rawset(data, key, value)
end
end
}
return setmetatable(proxy, metatable) -- setmetatable() simply returns `proxy`
end

通过这种方式,您有三个表:代理元表数据。用户访问代理,但由于每次访问都是完全空的,因此调用元表中的__index__newindex元方法。这些处理程序访问数据表,以检索或设置用户感兴趣的实际值。

以与以前相同的方式运行此操作,您将得到改进:

local root = make_proxy{}
root.first = 1                   -- table: 0xa40c30 first   =   1
root.second = 2                  -- table: 0xa40c30 second  =   2
root.nested_table = {}           -- /nothing/
root.nested_table.another = 4    -- table: 0xa403a0 another =   4
root.first = 5                   -- table: 0xa40c30 first   =   5

这应该会让你概述为什么你应该在这里使用代理表,以及如何处理它的元方法

剩下的就是如何识别您正在访问的字段的路径。这一部分包含在另一个问题的另一个答案中。我看不出有什么理由重复它。

最新更新