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

LUA-创建元表,使每个子表再次成为元表,lua,metatable,Lua,Metatable,但这肯定会让人困惑 我对LUA还很陌生,有一件事我还没有做很多工作,那就是元表 我需要找到一种方法来创建一个元表,它运行一个编辑值的函数。这不是一个问题,如果我停留在“一级”,所以第一个索引。然后,我可以简单地使用_newindex来运行它。但我要做的是在任何值更改时运行函数 这需要某种方法将元表中的任何表再次设置为与“main”元表运行相同功能的元表 在我的用例中,这将是一个“保存”功能: function MySaveFunction(tbl) FileSave(my_settings

但这肯定会让人困惑

我对LUA还很陌生,有一件事我还没有做很多工作,那就是元表

我需要找到一种方法来创建一个元表,它运行一个编辑值的函数。这不是一个问题,如果我停留在“一级”,所以第一个索引。然后,我可以简单地使用_newindex来运行它。但我要做的是在任何值更改时运行函数

这需要某种方法将元表中的任何表再次设置为与“main”元表运行相同功能的元表

在我的用例中,这将是一个“保存”功能:

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)


希望有人能帮我首先要注意的是
\uuuu newindex
\uuu index
元方法只有在处理目标表中的
nil
值时才会触发。如果要跟踪每一个更改,不能只使用
\uuuu newindex
,因为一旦编写了值,后续调用将不会起任何作用。相反,您需要使用代理表

另一个重要的考虑因素是访问成员的跟踪路径。

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

让我们用一个简单的例子来说明问题:

localmt={}
函数mt.\uu newindex(t、键、值)
如果类型(值)=“表”,则
rawset(t,key,setmetatable(value,mt))--为嵌套表设置元表
--在这里使用`t[key]=setmetatable(value,mt)`会导致溢出。
其他的
print(t,key,“=”,value)——我们希望在stdout中看到每次写入的输出
rawset(t、键、值)
结束
结束
本地根=setmetatable({},mt)
root.first=1--表:0xa40c30 first=1
root.second=2——表:0xa40c30 second=2
root.nested_table={}--/nothing/
root.nested_table.other=4--表:0xa403a0 other=4
root.first=5--/nothing/
现在,我们需要处理这些问题。让我们从创建代理表的方法开始:

本地
函数make_proxy(数据)
本地代理={}
本地元表={
__index=函数(_,键)返回rawget(数据,键)结束,
__newindex=函数(x,键,值)
如果类型(值)=“表”,则
rawset(数据、键、生成代理(值))
其他的
打印(数据,键,“=”,值)--或在此处使用保存功能!
rawset(数据、键、值)
结束
结束
}
return setmetatable(proxy,metatable)——setmetatable()只返回`proxy`
结束
这样就有了三个表:代理、元表和数据。用户访问代理,但由于每次访问时代理完全为空,因此调用了metatable中的元方法。这些处理程序访问数据表以检索或设置用户感兴趣的实际值

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

localroot=make_proxy{}
root.first=1--表:0xa40c30 first=1
root.second=2——表:0xa40c30 second=2
root.nested_table={}--/nothing/
root.nested_table.other=4--表:0xa403a0 other=4
root.first=5——表:0xa40c30 first=5
这应该让您概括了解为什么要在这里使用代理表,以及如何处理代理表的元方法


剩下的是如何识别正在访问的字段的路径。这一部分将在本节中介绍。我看不出复制它的理由。

是否应该再次调用
MyTable.Value=value2
MySaveFunction?是的,每次编辑/更改/创建/删除都应该调用它。您需要使用一个代理表,并将其与其他上下文一起传递。类似的东西应该可以做这项工作。如果到时候你还没有答案,我下班后会试试。非常感谢!这仍然是一个有点混乱和很多,但它至少给了我一个很好的指导,以解决问题@frenkey,我认为还有一件事值得澄清,因为您所写的内容表明您可能误解了它:当您执行
setmetatable(a,b)
时,您指定一个表
b
作为表
a
的元表<代码>a不会成为元表-它分配了一个元表。无论如何,这些都不是最简单的事情,慢慢来,自己阅读,自己做实验。元表是非常有趣的,一旦你把你的头围绕他们@frenkey,我更新了代理示例,希望它更具描述性,请查看。谢谢!我会试着绕着它转!我确实已经看到了元表的潜力,但它与我以前使用的其他所有东西都是如此不同