При написании обращенной к 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***
функции.