【问题标题】:Using C variable inside Lua alongside nested functions在 Lua 中使用 C 变量和嵌套函数
【发布时间】:2012-11-23 17:14:18
【问题描述】:

这是我之前关于在此处找到的嵌套注册 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 中设置变量值和函数之间实际上没有区别 - 命名函数只是已分配给变量的匿名函数。我不确定,但听起来你的问题是你使用 __newindex 在 dog 而不是 dog.beagle 上设置元表

标签: c variables lua nested


【解决方案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 闭包推入 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 成员,您将不得不做更多的错误检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-02
    • 2011-09-06
    • 2014-03-01
    • 2014-03-26
    • 2016-07-01
    • 1970-01-01
    相关资源
    最近更新 更多