Итерация через таблицу Lua
Я пытаюсь выполнить итерацию через таблицу lua, но я продолжаю получать эту ошибку:
invalid key to 'next'
Я знаю, что индекс начинается как -8, и я знаю, что там есть таблица, потому что она получает первое (и единственное) значение в ней. Тем не менее, он пытается повторить цикл, хотя я знаю, что в таблице есть только одна строка.
if (lua_istable(L, index))
{
lua_pushnil(L);
// This is needed for it to even get the first value
index--;
while (lua_next(L, index) != 0)
{
const char *item = luaL_checkstring(L, -1);
lua_pop(L, 1);
printf("%sn", item);
}
}
else
{
luaL_typerror(L, index, "string table");
}
любая помощь будет оценили.
это отлично работает, когда я использую положительный индекс (если я не удаляю 1 из это)
Edit: я заметил, что я не получаю эту ошибку, если я оставлю значение элемента в покое. Только когда я начинаю читать значение элемента я получаю эту ошибку. Когда у меня есть значение из таблицы, я вызываю другую функцию Lua, может ли это нарушить lua_next?
4 ответов
не используйте luaL_checkstring
с отрицательными аргументами. Использовать lua_tostring
вместо.
кроме того, убедитесь, что стек остается неизменным после вызова функции в цикле: lua_next
ожидает предыдущий ключ таблицы в верхней части стека, чтобы он мог возобновить обход.
есть 2 вещи, которые вы должны посмотреть:
- убедитесь, что исходный ключ оставлен в стеке перед следующим вызовом
lua_next
.luaL_checkstring
преобразует нестроковые ключи в строки (поскольку результирующая строка не находится в таблице, она становится недопустимым ключом.) Это легче всего сделать, пройдяluaL_checkstring
дубликат вместо оригинала. - убедитесь, что вы сохраняете структуру стека (т. е. pop столько значений, сколько вы нажимаете) на каждом проходе через петля
ваша функция будет работать только для отрицательных значений index
. Вы правы, что index--;
гарантирует, что index
по-прежнему указывает на таблицу после нажатия клавиши, но только если index
был отрицательным (т. е. относительно вершины стека.) Если index
является абсолютным или псевдо-индексом, тогда это заставит его указать на неправильный элемент. Самый простой обходной путь-нажать другую ссылку на таблицу в верхней части стека.
здесь минимальная программа C для демонстрации:
#include <lauxlib.h>
#include <lua.h>
static void iterate_and_print(lua_State *L, int index);
int main(int ac, char **av)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
// Create a table and put it on the top of the stack
luaL_loadstring(L, "return {one=1,[2]='two',three=3}");
lua_call(L, 0, 1);
iterate_and_print(L, -1);
return 0;
}
static void iterate_and_print(lua_State *L, int index)
{
// Push another reference to the table on top of the stack (so we know
// where it is, and this function can work for negative, positive and
// pseudo indices
lua_pushvalue(L, index);
// stack now contains: -1 => table
lua_pushnil(L);
// stack now contains: -1 => nil; -2 => table
while (lua_next(L, -2))
{
// stack now contains: -1 => value; -2 => key; -3 => table
// copy the key so that lua_tostring does not modify the original
lua_pushvalue(L, -2);
// stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
const char *key = lua_tostring(L, -1);
const char *value = lua_tostring(L, -2);
printf("%s => %s\n", key, value);
// pop value + copy of key, leaving original key
lua_pop(L, 2);
// stack now contains: -1 => key; -2 => table
}
// stack now contains: -1 => table (when lua_next returns 0 it pops the key
// but does not push anything.)
// Pop table
lua_pop(L, 1);
// Stack is now the same as it was on entry to this function
}
С руководство:
const char *lua_tolstring (lua_State *L, int index, size_t *len);
преобразует значение Lua в данной приемлемо указатель на C-строку. Если лен не NULL, он также устанавливает *len с длина строки. Значение Lua должно быть строкой или числом; в противном случае, функция возвращает значение NULL. Если значение-это число, затем lua_tolstring также изменяет фактическое значение в стек в строку. (это изменение путает lua_next, когда lua_tolstring применяется к ключам во время стол поперечный.)
luaL_checkstring
звонки lua_tolstring
.
см. также пример из документов для lua_next
, вот выдержки:
int lua_next (lua_State *L, int index);
выскакивает ключ из стека и выталкивает пару ключ–значение из таблицы по заданному индексу ("следующая" пара после заданного ключа). Если в таблице больше нет элементов, то
lua_next
возвращает 0 (и ничего не толкает).типичный обход выглядит так:
/* table is in the stack at index 't' */ lua_pushnil(L); /* first key */ while (lua_next(L, t) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); }
во время обхода таблицы не звоните
lua_tolstring
непосредственно на ключе, если вы не знаете, что ключ строки. Вспомните этоlua_tolstring
может изменить значение в данном индексе; это путает следующий вызовlua_next
.функции
next
для предостережений об изменении таблицы во время ее обхода.