这是我之前关于嵌套注册 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 检索它的值。我已经尝试过 __index 和 __newindex 元方法概念,但是当我在变量的 Lua 路径中有 2 个点时,我尝试的一切似乎都会崩溃。我知道我可能用两个点让它变得更复杂,但是它使 Lua 代码的组织更容易阅读。我还需要获取分配事件,因为当 microchipIDNumber 值发生变化时,我需要启动一些硬件。我假设我可以在设置值时通过 __newindex 来完成此操作。
关于如何编写元表和方法来完成嵌套有什么想法吗?难道是因为我之前的函数声明让Lua混淆了?
最佳答案
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 只是尝试调用返回值。所以不要使用:
对于成员(member)。
抛开这些,让我们看看如何在 Lua 和 C 之间同步变量。这实际上非常复杂,并且有不同的方法可以实现。一种解决方案是使用 __index
的组合和__newindex
。如果您有beagle
对于 C 中的结构,我建议创建这些 C 函数并将它们作为 C 闭包推送到 Lua 表的元表中,并使用指向 C 结构的指针作为上值。看this有关 lua_pushcclosure
的一些信息和 this一般而言,关于 Lua 中的闭包。
如果您没有可以引用的单个结构,它会变得更加复杂,因为您必须以某种方式存储对 variableName-variableLocation
在 C 端并知道每个是什么类型。你可以在实际的Lua表中维护这样一个列表,所以 dog.beagle
将是变量名称到一两个东西的映射。对于这个“东西”有几个选择。首先 - 一个轻量用户数据(即 - 一个 C 指针),但随后你会遇到弄清楚它指向什么的问题,以便你知道要推送什么 Lua 类型 __index
以及要弹出什么__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(对象,元表)。 2. 注意 rawget
的用法。我们需要它,因为否则会尝试从 __index
中获取对象的字段将是无限递归。 3. 您必须在事件rawget(table,key)
中进行更多的错误检查。返回nil
,或者如果它返回的内容没有 get
/set
成员。
关于c - 在 Lua 中与嵌套函数一起使用 C 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13499047/