Итерация через таблицу 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 для предостережений об изменении таблицы во время ее обхода.