但这肯定会让人感到困惑。
我对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
这应该会让你概述为什么你应该在这里使用代理表,以及如何处理它的元方法
剩下的就是如何识别您正在访问的字段的路径。这一部分包含在另一个问题的另一个答案中。我看不出有什么理由重复它。