在 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
函数的优势在于,在一行中,它们:
- 如果类型错误,则抛出一条信息丰富、用户友好的错误消息,并且
- 提供可立即使用的 C 语言友好 return 值。
我正在为 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 ..
}
这是一个可以检查参数是否为 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
函数的优势在于,在一行中,它们:
- 如果类型错误,则抛出一条信息丰富、用户友好的错误消息,并且
- 提供可立即使用的 C 语言友好 return 值。
我正在为 table 寻找类似的东西。我不期望 C 语言友好的散列-table return 值,但我 do 希望在参数中向用户提供相同质量的错误消息问题不可索引。
我正在接受鸭子打字的哲学。如果我编写的函数只是想从一个参数中索引一些键,那么我不关心该参数是否真的是一个 table,或者只是一个支持 __index
查找的用户数据。我想接受任何一个。
一般来说,只有 table 有查找,因为它是定义此 属性 的唯一类型。用户数据是不透明的,只有主机知道如何处理它或为特定行为添加元table(可以分析)。 CData 是使用 LuaJIT 编译的 Lua 的一部分,我从未在 C API 中使用过这种类型(甚至支持吗?)。最后,您必须检查 type/metatable 以进行可能的查找并请求一个字段来检查设置,没有办法绕过 lua_getfield
(但原始访问应该更快,请参阅 lua_rawget
)。例外情况是通过 lua_objlen
.
此外,更便宜的类型检查解决方案是 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 ..
}