6

"stackoverflow.test"我有一个具有某种元表类型(例如)的 Lua 用户数据对象。从 C 代码中,我希望能够准确检查它是哪种类型,并根据结果表现出不同的行为。是否有一个很好的方便函数(很像luaL_checkudata,但如果答案不是您想要的,则不会出错)让我查询用户数据的元表类型名称?如果没有,我想我需要使用lua_getmetatable,但是我有点不清楚如何确定刚刚添加到堆栈中的元表的名称。

澄清一下:我使用的是 Lua 5.1,其中 luaL_checkudata 的行为发生了变化。我知道在 5.0 中它不会出错。

4

4 回答 4

5

您始终可以在元表中存储一个标记字段,其中包含模块独有的轻量用户数据值。

static const char *green_flavor = "green";
...
void my_setflavor(lua_State *L, void *flavor) {
  lua_pushlightuserdata(L,flavor);
  lua_pushlstring(L,"_flavor");
  lua_rawset(L,-3);
}

void my_isflavor(lua_State *L, void *flavor) {
  void *p = NULL;
  lua_pushlstring(L,"_flavor");
  lua_rawget(L,-2);
  p = lua_touserdata(L,-1);
  lua_pop(L,1);
  return p == flavor;
}

然后可以使用my_setflavor(L,&green_flavor)设置栈顶表的_flavor字段,并my_isflavor(L,&red_flavor)测试栈顶表的_flavor字段。

以这种方式使用,_flavor 字段只能采用可以由模块中具有符号 green_flavor 的代码创建的值,并且除了检索元表本身之外,查找该字段并测试其值只需要一次表查找. 请注意,变量 green_flavor 的值无关紧要,因为实际上只使用了它的地址。

有几个不同的风味变量可用作标记值,_flavor 字段可用于区分几个相关的元表。

综上所述,一个自然的问题是“为什么要这样做?” 毕竟,元表可以很容易地包含获得适当行为所需的所有信息。它可以很容易地保存函数和数据,并且可以从 C 和 Lua 中检索和调用这些函数。

于 2009-04-08T01:43:45.603 回答
3

您将使用lua_getmetatableandlua_equal来测试表是否相同。

在我看来,Lua 应该对这种类型扩展的东西给予更多的支持。到目前为止,这确实是 Lua/C(++) 包装系统的责任。

在我最近完成的包装器中(作为商业项目的一部分),我这样做是class::instance(L,index)为了获取特定类型的用户数据指针。换句话说,该方法检查它是用户数据并且元表也是正确的。如果不是,则返回 NULL。

Lua 可以帮助这一切的方式是,如果元表有一个用于扩展类型信息(sa __type)的标准字段。这可以用来type()返回“userdata”、“xxx”(两个值,目前只返回一个)。这将与大多数当前代码保持兼容。但这只是假设(除非您执行自定义 type() 并自行实现)。

于 2009-04-09T07:20:48.767 回答
2

用户数据必须有一个元表,所以抓住它;然后在注册表中查找您想要的名称。如果这两个对象相同,则您已找到要查找的类型。

您可以在 C 代码中发送这种类型,但请允许我建议您改为指定元表的字段。存储在元表中的函数应该可以完成这项工作,但如果不是,如果您绝对必须switch在 C 代码中使用,则选择一个名称,使用该名称来索引元表,并为每个元表分配一个可以打开的小整数。

meta1.decision = 1
meta2.decision = 2
meta3.decision = 3

然后在你的 C 代码中

if (lua_getmetatable(L, 1)) {
  lua_getfield(L, -1, "decision");
  if (lua_isnumber(L, -1)) {
    switch ((int) lua_tonumber(L, -1)) {
       case 1: ... ; break;
       case 2: ... ; break;
       case 3: ... ; break;
    }
    return 0;
  }
}
return luaL_error(L, "Userdata was not one of the expected types");
于 2009-04-09T02:05:56.760 回答
0

我刚刚查看了luaL_checkudata函数的源代码,它基本上使用lua_getmetatable. 然后它使用 来从注册表中获取给定的类型名称lua_getfield,并lua_rawequal调用来比较它们。

于 2009-04-07T18:17:30.233 回答