2011-05-26 22 views
13

Estoy tratando de recorrer una tabla lua, pero me siguen dando este error:iterar a través de la tabla Lua

invalid key to 'next' 

sé que el índice comienza como -8 y sé que hay una mesa allí porque obtiene el primer (y único) valor en él. Sin embargo, intenta dar vueltas nuevamente aunque sé que solo hay una cadena en la tabla.

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"); 
} 

Cualquier ayuda sería apreciada.

Esto funciona bien cuando se utiliza un índice positivo (siempre y cuando no quito 1 de ella)

Editar: me he dado cuenta de que no me sale este error si deje el valor del artículo solo. Solo cuando empiezo a leer el valor del artículo obtengo este error. Cuando obtengo el valor de la tabla, llamo a otra función Lua, ¿podría estar interrumpiendo lua_next?

Respuesta

5

No utilice luaL_checkstring con argumentos negativos. Use lua_tostring en su lugar.

Además, asegúrese de que la pila siga siendo la misma después de llamar a una función en el ciclo: lua_next espera la clave de tabla anterior en la parte superior de la pila para que pueda reanudar el recorrido.

+0

Sí, después de volcar el contenido de la pila antes y después , Noté que hay restos de cuando llamé a la función. –

2

Desde el manual:

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

Converts the Lua value at the given acceptable index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; otherwise, the function returns NULL. If the value is a number, then lua_tolstring also changes the actual value in the stack to a string. (This change confuses lua_next when lua_tolstring is applied to keys during a table traversal.)

luaL_checkstring llamadas lua_tolstring.

+0

Lo sentimos, como dice la cita, esto solo se aplica a la clave, y está ejecutando esto en el valor. – BMitch

30

Hay 2 cosas que hay que ver:

  • garantizar la llave original se deja en la pila antes de la siguiente llamada a lua_next. luaL_checkstring convertirá claves que no son de cadena a cadenas (como la cadena resultante no está en la tabla, se convierte en una clave no válida). Esto se hace más fácilmente al pasar luaL_checkstring una copia de la clave en lugar de la original.
  • garantizar que conserva la estructura de pila (es decir, explotar todos los valores a medida que empuja) en cada paso a través del bucle

Su función sólo funcionará para los valores negativos de index. Tiene razón en que index--; se asegurará de que index aún apunte a la tabla después de presionar la tecla, pero solo si index fue negativo (es decir, relativo a la parte superior de la pila). Si index es un índice absoluto o pseudo, esto lo causará para señalar el artículo incorrecto. La solución más fácil es enviar otra referencia a la tabla en la parte superior de la pila.

Aquí es un programa mínimo C para demostrar:

#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 
} 
+0

'luaL_checkstring' acepta índices negativos pero se cancela y da el mensaje incorrecto si falla porque está destinado a verificar los argumentos de función, no para la conversión general. – lhf

+0

@lhf, OK, parece que no hay ninguna ventaja en el uso de 'luaL_checkstring' más que en el código de muestra de la pregunta. Reemplazado con 'lua_tostring'. – finnw

-1

Véase también el ejemplo de la documentación para lua_next, un extracto aquí:

int lua_next (lua_State *L, int index);

Pops a key from the stack, and pushes a key–value pair from the table at the given index (the "next" pair after the given key). If there are no more elements in the table, then lua_next returns 0 (and pushes nothing).

A typical traversal looks like this:

/* 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); 
} 

While traversing a table, do not call lua_tolstring directly on a key, unless you know that the key is actually a string. Recall that lua_tolstring may change the value at the given index; this confuses the next call to lua_next .

See function next for the caveats of modifying the table during its traversal.

Cuestiones relacionadas