简体   繁体   English

用C编写面向Lua的函数时,检查参数是否支持表式查找的好方法是什么?

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

Here's a potential pattern that can check if an argument is a table: 这是一种可能的模式,可以检查参数是否为表:

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

This works whenever the first argument is a table. 只要第一个参数是表,此方法就起作用。 However, other Lua types support table lookups, such as a userdata, and in luajit, a cdata. 但是,其他Lua类型也支持表查找,例如userdata和luajit中的cdata。

Is there a nice way to check if a table lookup, such as via lua_getfield , will succeed before I call it? 有没有一种很好的方法来检查表查找(例如通过lua_getfield )是否会在我调用它之前成功? I mean without restricting the type to tables. 我的意思是不将类型限制为表格。 Relatedly, are tables, userdata, and cdata the only types in luajit that support indexed lookups? 相关地,表,用户数据和cdata是luajit中唯一支持索引查找的类型吗?

I'm most interested in answers restricted to the Lua 5.1 C API because I'm using LuaJIT which currently works with this version. 我对仅限于Lua 5.1 C API的答案最感兴趣,因为我使用的是当前与此版本兼容的LuaJIT。

Clarification 澄清

The advantage of the luaL_checkXXX functions is that, in one line, they: luaL_checkXXX函数的优势在于,它们可以在一行中:

  • throw an informative, user-friendly error message if the type is wrong, and 如果类型错误,则抛出信息丰富,用户友好的错误消息,并且
  • provide a C-friendly return value that can be used immediately. 提供C友好的返回值,可以立即使用。

I'm looking for something similar for tables. 我正在寻找类似的表。 I don't expect a C-friendly hash-table return value, but I do want the same quality of error message to the user if the argument in question is not indexable. 我不期望C友好的哈希表返回值,但是如果有问题的参数不可索引,我确实希望向用户提供相同质量的错误消息。

I'm embracing the philosophy of duck typing. 我正在接受鸭子打字的哲学。 If I write a function that simply wants to index some keys from an argument, then I don't care if that argument is truly a table, or just a userdata that supports __index lookups. 如果我编写的函数只是想对某个参数中的某些键编制索引,那么我不在乎该参数是否真正是一个表,或者仅仅是支持__index查找的userdata。 I want to accept either one. 我要接受任何一个。

In general, just tables have lookups because it's the only type which defines this property. 通常,只有表才具有查找功能,因为它是定义此属性的唯一类型。 Userdata are opaque, just the host knows what to do with it or adds a metatable (which can be analyzed) for specific behaviour. 用户数据是不透明的,只有主机知道如何处理或为特定行为添加一个元表(可以分析)。 CData are part of Lua compiling with LuaJIT, i never used this type with C API (is it even supported?). CData是使用LuaJIT编译的Lua的一部分,我从来没有将此类型与C API一起使用(甚至支持它吗?)。 At the end you have to check the type/metatable for possible lookups and request a field to check for setting, there's no way around lua_getfield (but raw access should be faster, see lua_rawget ). 最后,您必须检查类型/可匹配类型以进行可能的查找,并请求一个字段来检查设置,但是lua_getfield周围没有办法(但是原始访问应该更快,请参见lua_rawget )。 The exception would be to check for table array length by lua_objlen . 例外是通过lua_objlen检查表数组的长度。

Furthermore a cheaper solution for type checking would be lua_is*** functions. 此外,更便宜的类型检查解决方案是lua_is***函数。

Here's one way to do it: 这是一种实现方法:

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

This works for tables and any value with an __index value on its metatable. 这适用于表以及在其元__index上具有__index值的任何值。

It provides a standard-format error given by luaL_argerror . 它提供了luaL_argerror给出的标准格式错误。 Here's an example error message: 这是示例错误消息:

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

You can use it like this: 您可以像这样使用它:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM