这是我之前关于嵌套注册C函数的问题的后续跟进: Trying to call a function in Lua with nested tables
上一个问题给了我添加这样的嵌套函数的答案:
dog.beagle.fetch()
我也想在这个级别拥有变量,如:
dog.beagle.name
dog.beagle.microchipID
我希望这个字符串和数字在C中分配并由Lua访问。因此,在C代码中,变量可以定义为:
int microchipIDNumber;
char dogname[500];
C变量需要通过Lua中的赋值进行更新,当Lua位于等号右侧时,需要由Lua检索其值。我已经尝试了__index和__newindex元方法概念,但是当我在变量的Lua路径中有2个点时,我尝试的所有内容似乎都会崩溃。我知道我可能会使2点更复杂,但它使组织更容易阅读Lua代码。我还需要获得一个事件来分配,因为我需要在microchipIDNumber值改变时启动一些硬件。我假设我可以在设置值时通过__newindex执行此操作。
关于如何编写元表和方法来完成嵌套的任何想法?可能是因为我以前的函数声明让Lua感到困惑吗?
答案 0 :(得分:1)
Lua中的冒号运算符(:
)仅用于函数。请考虑以下示例:
meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)
索引函数将简单地打印它传递的两个参数并返回第二个参数(我们也将打印,因为只是执行object.foo
是语法错误)。新输出的输出为table: 0x153e6d0 foo foo
。所以__index
获取我们正在查找变量及其名称的对象。现在,如果我们将object.foo
替换为object:foo
,我们就会得到:
input:5: function arguments expected near ')'
这是因为:
中的object:foo
是object.foo(object)
的语法糖,所以Lua希望您为函数调用提供参数。如果我们确实提供了参数(object:foo("bar")
),我们就会得到:
table: 0x222b3b0
foo
input:5: attempt to call method 'foo' (a string value)
所以我们的__index
函数仍然被调用,但是没有传递参数 - Lua只是试图调用返回值。因此,请勿将:
用于成员。
有了这个,让我们看看你如何在Lua和C之间同步变量。这实际上是非常复杂的,并且有不同的方法来实现它。一种解决方案是使用__index
和__newindex
的组合。如果在C中有beagle
结构,我建议使用这些C函数并将它们作为C-closure推送到Lua表的元表中,并将指向C结构的指针作为upvalue。有关lua_pushcclosure
和this关于Lua闭包的一些信息,请查看this。
如果你没有可以引用的单一结构,那么它会变得更加复杂,因为你必须以某种方式在C方面存储对variableName-variableLocation
并知道它们的类型。您可以在实际的Lua表中维护这样的列表,因此dog.beagle
将是一个或两个变量名称的映射。这个'某事'有几种选择。首先 - 一个轻量级用户数据(即 - 一个C指针),但是你会遇到问题指出的问题,以便你知道要为__index
推送什么Lua类型以及什么到弹出__newindex
。另一个选择是推送两个函数/闭包。你可以为每个你必须处理的类型(数字,字符串,表等)创建一个C函数,并为每个变量推送一个适当的函数,或者创建一个uber-closure,它接受一个参数给出的类型然后给出只是改变你推动它的上升值。在这种情况下,__index
和__newindex
函数将只查找给定变量名称的相应函数并调用它,因此在Lua中实现它可能最容易。
对于两个函数,dog.beagle
可能看起来像这样(不是实际的Lua语法):
dog.beagle = {
__metatable = {
__index = function(table,key)
local getFunc = rawget(table,key).get
return getFunc(table,key)
end
__newindex = function(table,key,value)
local setFunc = rawget(table,key).set
setFunc(table,key,value)
end
}
"color" = {
"set" = *C function for setting color or closure with an upvalue to tell it's given a color*,
"get" = *C function for getting color or closure with an upvalue to tell it to return a color*
}
}
关于上述内容的注释: 1.不要直接设置对象的__metatable
字段 - 它用于隐藏真正的元表。使用setmetatable(object,metatable)。 2.注意rawget
的用法。我们需要它,因为否则尝试从__index
内获取对象的字段将是无限递归。 3.如果事件rawget(table,key)
返回nil
,或者返回的内容没有get
/ set
成员,则必须进行更多错误检查。< / p>