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 闭包推入 Lua 表的元表中,并将指向您的 C 结构的指针作为上值。查看this 了解有关lua_pushcclosure 和this 的一般Lua 闭包的一些信息。
如果您没有可以引用的单一结构,它会变得更加复杂,因为您必须以某种方式在 C 端存储对 variableName-variableLocation 并知道每个是什么类型。您可以在实际的 Lua 表中维护这样的列表,因此 dog.beagle 将是变量名称到一两个东西的映射。这个“东西”有几个选择。首先 - 一个轻量级用户数据(即 - 一个 C 指针),但随后您将遇到弄清楚它指向什么的问题,以便您知道要为 __index 推送什么 Lua 类型以及要弹出什么对于__newindex。另一种选择是推送两个函数/闭包。您可以为必须处理的每种类型(数字、字符串、表格等)创建一个 C 函数,并为每个变量推送适当的函数,或者创建一个超级闭包,它接受一个参数,然后给出它的类型只是改变你推动它的价值。在这种情况下,__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 成员,您将不得不做更多的错误检查。