遍历 Lua 表格

我正在尝试遍历一个lua表,但我一直收到以下错误:

` 无效键'下一个' `

我知道索引起始为-8,我知道那里有一个表,因为它得到了第一个(也是唯一的)值。但是,即使我知道表中只有一个字符串,它仍然尝试循环回来。

`` ` 如果(lua_istable(L,index)) {     lua_pushnil(L);

    //这是必需的,以便它甚至可以获得第一个值     索引-;

    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的值放置不变的情况下,我才不会收到此错误。只有在我开始读取item的值时才会发生这种错误。当我从表中获取值时,我调用另一个Lua函数,这可能会干扰lua \ _next吗?

原文链接 https://stackoverflow.com/questions/6137684

点赞
stackoverflow用户107090
stackoverflow用户107090

不要在负参数中使用 luaL_checkstring。改用 lua_tostring

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

2011-05-26 12:44:38
stackoverflow用户596285
stackoverflow用户596285

手册中:

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

将给定可接受索引处的Lua值转换为C字符串。如果len不为NULL,则还将其设置为字符串长度。Lua值必须是字符串或数字;否则,该函数将返回NULL。如果该值是数字,则lua_tolstring还会将堆栈中的实际值更改为字符串。(当在表遍历期间应用于键时,此更改使lua_next混淆。)

luaL_checkstring调用lua_tolstring

2011-05-26 12:56:04
stackoverflow用户12048
stackoverflow用户12048

有两个需要注意的事项:

  • 在下一次调用 lua_next 之前确保原始键还留在堆栈上。luaL_checkstring 会将非字符串键转换为字符串(因为生成的字符串不在表中,所以它将成为无效的键)。最简单的方法是向 luaL_checkstring 传递键的副本而不是原始键。
  • 确保在循环每次通过时保留堆栈结构(即推入多少值就弹出多少值)。

你的函数只适用于负的 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);

   // 创建一个表并把它放在堆栈顶部
   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)
{
    // 推一个对表的另一个引用到堆栈顶部(以确保我们知道它在哪里,这个函数可以适用于负、正和伪索引)
    lua_pushvalue(L, index);
    // 堆栈现在包含:-1 => 表
    lua_pushnil(L);
    // 堆栈现在包含:-1 => nil;-2 => 表
    while (lua_next(L, -2))
    {
        // 堆栈现在包含:-1 => 值;-2 => 键;-3 => 表
        // 复制键,这样 lua_tostring 就不会修改原始键
        lua_pushvalue(L, -2);
        // 堆栈现在包含:-1 => 键;-2 => 值;-3 => 键;-4 => 表
        const char *key = lua_tostring(L, -1);
        const char *value = lua_tostring(L, -2);
        printf("%s => %s\n", key, value);
        // 弹出值 + 键的副本,留下原始键
        lua_pop(L, 2);
        // 堆栈现在包含:-1 => 键;-2 => 表
    }
    // 堆栈现在包含:-1 => 表(当 lua_next 返回 0 时,它会弹出键但不会推入任何东西)
    // 弹出表
    lua_pop(L, 1);
    // 堆栈现在与进入该函数时相同
}
2011-05-26 17:33:52
stackoverflow用户459863
stackoverflow用户459863

lua_next 的文档中摘录了以下示例:

int lua_next (lua_State *L, int index);

从堆栈中弹出一个键,并从给定索引处的表(给定键值之后的“下一个”键值对)推送一个键值对。 如果表中没有更多元素,则 lua_next 返回 0(并且不推送任何内容)。

典型的遍历如下所示:

/* 将表在 't' 索引处压入堆栈 */
 lua_pushnil(L);  /* 第一个键 */
 while (lua_next(L, t) != 0) {
   /* 使用 'key'(在索引 -2 处)和 'value'(在索引 -1 处) */
   printf("%s - %s\n",
          lua_typename(L, lua_type(L, -2)),
          lua_typename(L, lua_type(L, -1)));
   /* 删除 'value';保留 'key' 以备下次迭代 */
   lua_pop(L, 1);
 }

在遍历表时,不要直接在键上调用 lua_tolstring,除非你知道键实际上是一个字符串。请记住,lua_tolstring 可能会更改给定索引处的值;这会使下一个调用 lua_next 混淆。

有关修改表时的注意事项,请参见函数 next

2016-05-03 20:40:50