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

When writing a Lua-facing function in C, what's a good way to check if an argument supports table-like lookups?

这是一个可以检查参数是否为 table:

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

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

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

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

澄清

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

我正在为 table 寻找类似的东西。我不期望 C 语言友好的散列-table return 值,但我 do 希望在参数中向用户提供相同质量的错误消息问题不可索引。

我正在接受鸭子打字的哲学。如果我编写的函数只是想从一个参数中索引一些键,那么我不关心该参数是否真的是一个 table,或者只是一个支持 __index 查找的用户数据。我想接受任何一个。

一般来说,只有 table 有查找,因为它是定义此 属性 的唯一类型。用户数据是不透明的,只有主机知道如何处理它或为特定行为添加元table(可以分析)。 CData 是使用 LuaJIT 编译的 Lua 的一部分,我从未在 C API 中使用过这种类型(甚至支持吗?)。最后,您必须检查 type/metatable 以进行可能的查找并请求一个字段来检查设置,没有办法绕过 lua_getfield(但原始访问应该更快,请参阅 lua_rawget)。例外情况是通过 lua_objlen.

检查 table 数组长度

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

这是一种方法:

// 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 ..
}