При написании обращенной к Lua функции в C, каков хороший способ проверить, поддерживает ли аргумент поиск в виде таблицы?

Вот потенциальный шаблон, который может проверить, является ли аргумент таблицей:

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

Это работает всякий раз, когда первый аргумент является таблицей. Однако другие типы Lua поддерживают поиск в таблицах, например, userdata, а в luajit - cdata.

Есть хороший способ проверить, если поиск таблицы, например, через lua_getfield, преуспеет ли прежде, чем я это назову? Я имею в виду, не ограничивая тип таблицами. В связи с этим, являются ли таблицы, пользовательские данные и cdata единственными типами в luajit, которые поддерживают индексированный поиск?

Меня больше всего интересуют ответы, ограниченные API Lua 5.1 C, потому что я использую LuaJIT, который в настоящее время работает с этой версией.

осветление

Преимущество luaL_checkXXX функции в том, что в одной строке они:

  • бросить информативное, удобное для пользователя сообщение об ошибке, если тип неправильный, и
  • предоставить C-friendly возвращаемое значение, которое можно использовать немедленно.

Я ищу что-то подобное для таблиц. Я не ожидаю возвращаемого значения C-friendly хеш-таблицы, но я хочу, чтобы сообщение об ошибке было такого же качества для пользователя, если рассматриваемый аргумент не индексируется.

Я придерживаюсь философии утки. Если я напишу функцию, которая просто хочет индексировать некоторые ключи из аргумента, то мне все равно, действительно ли этот аргумент является таблицей или просто пользовательскими данными, которые поддерживают __index поиск. Я хочу принять любой.

2 ответа

Решение

Вот один из способов сделать это:

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

В целом, только таблицы имеют поиск, потому что это единственный тип, который определяет это свойство. Пользовательские данные непрозрачны, просто хост знает, что с ними делать, или добавляет метатабельный (который можно проанализировать) для определенного поведения. CData являются частью Lua-компиляции с LuaJIT, я никогда не использовал этот тип с C API (он даже поддерживается?). В конце вы должны проверить тип /metatable для возможных поисков и запросить поле, чтобы проверить настройки, нет никакого способа обойти lua_getfield (но необработанный доступ должен быть быстрее, см. lua_rawget). Исключением будет проверка длины массива таблицы lua_objlen,

Кроме того, более дешевое решение для проверки типов будет lua_is*** функции.

Другие вопросы по тегам