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

时间:2015-09-25 22:43:42

标签: c lua luajit lua-api

这是一个潜在的模式,可以检查参数是否是一个表:

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

只要第一个参数是表,这就有效。但是,其他Lua类型支持表查找,例如userdata,在luajit中支持cdata。

在我调用之前,是否有一种很好的方法可以检查表查找(例如via lua_getfield)是否会成功?我的意思是不限制表格的类型。相关地,table,userdata和cdata是luajit中唯一支持索引查找的类型吗?

我最感兴趣的是限于Lua 5.1 C API的答案,因为我使用的LuaJIT目前适用于此版本。

澄清

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

  • 如果类型错误,则抛出信息性的,用户友好的错误消息,
  • 提供可以立即使用的C友好返回值。

我正在为桌子寻找类似的东西。我不希望C友好的哈希表返回值,但如果有问题的参数不可索引,我希望向用户提供相同质量的错误消息。

我接受了鸭子打字的哲学。如果我编写一个只想从参数中索引某些键的函数,那么我就不在乎该参数是真正的表,还是只关注支持__index查找的用户数据。我想接受其中任何一个。

2 个答案:

答案 0 :(得分:0)

通常,只有表具有查找,因为它是唯一定义此属性的类型。 Userdata是不透明的,只是主机知道如何处理它或者为特定行为添加metatable(可以分析)。 CData是Lua用LuaJIT编译的一部分,我从未在C API中使用过这种类型(它是否支持?)。最后,您必须检查类型/元表以查找可能的查找并请求字段检查设置,lua_getfield无法解决(但原始访问应该更快,请参阅lua_rawget)。例外情况是按lua_objlen检查表数组长度。

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

答案 1 :(得分:0)

这是一种方法:

// If the value at index narg is not indexable, this function does not return and
// provides a user-friendly error message; otherwise the stack is unchanged.
static void luaL_checkindexable(lua_State *L, int narg) {
  if (lua_istable(L, narg)) return;  // tables are indexable.
  if (!luaL_getmetafield(L, narg, "__index")) {
    // This function will show the user narg and the Lua-visible function name.
    luaL_argerror(L, narg, "expected an indexable value such as a table");
  }
  lua_pop(L, 1);  // Pop the value of getmetable(narg).__index.
}

这适用于表及其元表上具有__index值的任何值。

它提供luaL_argerror给出的标准格式错误。这是一个示例错误消息:

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

你可以像这样使用它:

// This Lua-facing function expects an indexable 1st argument.
int my_fn(lua_State *L) {
  luaL_checkindexable(L, 1);
  lua_getfield(L, 1, "key");  // --> arg1.key or nil is now on top of stack.
  // .. your fn ..
}