在C语言中编写面向Lua的函数时,有什么好方法可以检查参数是否支持类似表格的查找?

下面是一个可能的模式,可以检查参数是否为表:

int my_fn(lua_State *L) {
  luaL_checktype(L, 1, LUA_TTABLE);
  // .. do stuff with the table ..
}

只要第一个参数是表格,这就起作用了。然而,其他Lua类型也支持表查找,例如用户数据和luajit中的cdata。

是否有一种简洁的方法在调用之前检查表查找(例如通过lua_getfield)是否成功?我是指不限制类型为表的情况。相关的是,表、用户数据和cdata是luajit中仅支持索引查找的类型吗?

我最感兴趣的是限制在Lua 5.1 C API中的答案,因为我正在使用LuaJIT,它当前适用于此版本。

澄清

luaL_checkXXX函数的优点是,它们在一行中:

  • 如果类型错误,抛出信息丰富、用户友好的错误消息
  • 提供一个C友好的返回值,可以立即使用

我正在寻找类似于表格的东西。我不希望返回一个C友好的哈希表值,但是如果涉及的参数无法索引,我希望向用户提供相同质量的错误消息。

我 embrace ”鸭子类型“ 的哲学。如果我编写一个简单的函数,只希望从参数索引一些键,那么我不关心那个参数是真正的表还是只是支持__index查找的用户数据。我希望接受任何一个。

点赞
用户2546626
用户2546626

通常,只有表才具有查找属性,因为这是唯一定义了此属性的类型。UserData 是不透明的,只有主机知道如何处理它或添加元表(可以进行分析)以实现特定的行为。CData 是 LuaJIT 编译时的一部分,我从未使用过此类型的 C API(它是否受支持?)。最后,您必须检查类型/元表以进行可能的查找并请求字段以进行设置,无法避免 lua_getfield(但是原始访问应该更快,详见 lua_rawget)。例外是通过 lua_objlen 检查表数组长度。

此外,类型检查的更便宜的解决方案将是 lua_is*** 函数。

2015-09-26 01:14:54
用户3561
用户3561

以下是一种实现方法:

// 如果 narg 对应的值不可被索引,该函数会提供一个友好的错误信息并且不会返回;
// 否则不会改变栈的状态。
static void luaL_checkindexable(lua_State *L, int narg) {
  if (lua_istable(L, narg)) return;  // 表是可以被索引的。
  if (!luaL_getmetafield(L, narg, "__index")) {
    // 该函数将会向用户展示 narg 和可以在 Lua 中看到的函数名。
    luaL_argerror(L, narg, "expected an indexable value such as a table");
  }
  lua_pop(L, 1);  // 弹出 getmetable(narg).__index 对应的值。
}

该函数适用于表和那些具有元表 __index 值的值。

它提供了由 luaL_argerror 提供的标准格式的错误信息。以下是一个错误信息的例子:

a_file.lua:7: bad argument #1 to 'fn' (expected an indexable value such as a table)

你可以像这样使用它:

// 这个面向 Lua 的函数期望有一个可索引的第一个参数。
int my_fn(lua_State *L) {
  luaL_checkindexable(L, 1);
  lua_getfield(L, 1, "key");  // --> arg1.key 或 nil 现在在栈顶。
  // .. 你的 fn ..
}
2015-09-29 19:02:37