0

This is a sort of followup to my previous question about nested registered C functions found here: Trying to call a function in Lua with nested tables

The previous question gave me the answer to adding a nested function like this:

dog.beagle.fetch()

I also would like to have variables at that level like:

dog.beagle.name
dog.beagle.microchipID

I want this string and number to be allocated in C and accessible by Lua. So, in C code, the variables might be defined as:

int microchipIDNumber;
char dogname[500];

The C variables need to be updated by assignments in Lua and its value needs to be retrieved by Lua when it is on the right of the equal sign. I have tried the __index and __newindex metamethod concept but everything I try seems to break down when I have 2 dots in the Lua path to the variable. I know I am probably making it more complicated with the 2 dots, but it makes the organization much easier to read in the Lua code. I also need to get an event for the assignment because I need to spin up some hardware when the microchipIDNumber value changes. I assume I can do this through the __newindex while I am setting the value.

Any ideas on how you would code the metatables and methods to accomplish the nesting? Could it be because my previous function declarations are confusing Lua?

4

1 回答 1

1

Lua 中的冒号运算符 ( :) 仅用于函数。考虑以下示例:

meta = {}
meta["__index"] = function(n,m) print(n) print(m) return m end
object = {}
setmetatable(object,meta)
print(object.foo)

index 函数将简单地打印它传递的两个参数并返回第二个参数(我们也将打印它,因为这样做object.foo是语法错误)。输出将table: 0x153e6d0 foo foo带有新行。所以__index获取我们在其中查找变量的对象及其名称。现在,如果我们替换object.fooobject:foo我们得到这个:

input:5: function arguments expected near ')'

这是因为:inobject: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。如果您beagle在 C 中有一个结构,我建议您制作这些 C 函数并将它们作为 C 闭包推入 Lua 表的元表中,并将指向您的 C 结构的指针作为上值。看看这个关于 Lua 中的闭包的一些信息lua_pushcclosure这个

如果您没有可以引用的单一结构,它会变得更加复杂,因为您必须以某种方式variableName-variableLocation在 C 端存储对并知道每个是什么类型。您可以在实际的 Lua 表中维护这样的列表,因此dog.beagle将变量名映射到一两个东西的映射。这个“东西”有几个选择。首先 - 一个轻量级用户数据(即 - 一个 C 指针),但随后您将遇到弄清楚它指向什么的问题,以便您知道要推入的 Lua 类型__index以及弹出的内容__newindex. 另一种选择是推送两个函数/闭包。您可以为您必须处理的每种类型(数字、字符串、表格等)创建一个 C 函数,并为每个变量推送适当的函数,或者创建一个超级闭包,它接受一个参数,它被赋予什么类型,然后只是改变你推动它的价值。在这种情况下,__indexand__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将是无限递归。rawget(table,key)3. 您必须在事件返回时做更多的错误检查nil,或者如果它返回的内容没有get/set成员。

于 2012-11-23T09:14:18.307 回答