通过Lua表迭代

时间:2011-05-26 11:23:14

标签: c lua lua-table

我正在尝试遍历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("%s\n", item);
    }
}
else
{
    luaL_typerror(L, index, "string table");
}

任何帮助都将不胜感激。

当我使用正索引时(只要我不从中删除1),这样可以正常工作

编辑:我注意到如果单独留下项目的值,我就不会收到此错误。只有当我开始读取item的值时才会出现此错误。当我从表中获得值时,我调用另一个Lua函数,这会破坏lua_next吗?

4 个答案:

答案 0 :(得分:30)

您需要注意两件事:

  • 确保在下次调用lua_next之前原始密钥保留在堆栈中。 luaL_checkstring会将非字符串键转换为字符串(因为结果字符串不在表中,它将成为无效键。)通过传递luaL_checkstring密钥的副本而不是原文。
  • 确保在每次通过循环时保留堆栈结构(即弹出尽可能多的值)

您的功能仅适用于index的负值。您是正确的index--;将确保index在按下键后仍然指向该表,但仅当index为负时(即相对于堆栈的顶部。)如果{ {1}}是绝对或伪索引,然后它会导致它指向错误的项目。最简单的解决方法是将对表的另一个引用推送到堆栈的顶部。

这是一个最小的C程序来演示:

index

答案 1 :(得分:5)

请勿将luaL_checkstring与否定参数一起使用。请改用lua_tostring

此外,确保在循环中调用函数后堆栈保持不变:lua_next期望堆栈顶部的前一个表键,以便它可以恢复遍历。

答案 2 :(得分:2)

来自manual

const char *lua_tolstring (lua_State *L, int index, size_t *len);
  

转换给定的Lua值   C字符串的可接受索引。如果是len   不是NULL,它也设置* len   字符串长度。 Lua值必须   是一个字符串或数字;除此以外,   该函数返回NULL。如果   value是一个数字,然后是lua_tolstring   也改变了实际值   堆叠到一个字符串。 (此更改   当lua_tolstring时混淆lua_next   在表格中应用于键   遍历。)

luaL_checkstring来电lua_tolstring

答案 3 :(得分:-1)

另请参阅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