2011-05-26 5 views
13

Je suis en train de parcourir une table Lua mais je continue à obtenir cette erreur:Itérer par Lua Tableau

invalid key to 'next' 

Je sais que l'indice commence comme -8 et je sais qu'il ya une table là-bas parce qu'il obtient la première (et seule) valeur en elle. Cependant, il essaie de rebondir même si je sais qu'il n'y a qu'une seule chaîne dans la table.

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

Toute aide serait appréciée.

Cela fonctionne bien lorsque j'utilise un indice positif (tant que je ne retire pas 1 de celui-ci)

Edit: J'ai remarqué que je ne comprends pas cette erreur si je laissez la valeur de l'élément seul. Ce n'est que lorsque je commence à lire la valeur de l'article que j'obtiens cette erreur. Quand j'ai la valeur de la table, j'appelle une autre fonction de Lua, est-ce que cela pourrait perturber lua_next?

Répondre

5

N'utilisez pas luaL_checkstring avec des arguments négatifs. Utilisez lua_tostring à la place.

De même, assurez-vous que la pile reste la même après avoir appelé une fonction dans la boucle: lua_next attend la touche de la table précédente en haut de la pile afin qu'elle puisse reprendre la traversée.

+0

Oui, après avoir largué le contenu de la pile avant et après , J'ai remarqué qu'il y a des restes à partir de quand j'ai appelé la fonction. –

2

De l'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 appels lua_tolstring.

+0

Désolé, comme l'indique le devis, cela ne s'applique qu'à la clé, et vous l'exécutez sur la valeur. – BMitch

30

Il y a 2 choses que vous devez regarder:

  • Vérifier que la clé d'origine est laissée sur la pile avant le prochain appel à lua_next. luaL_checkstring convertit les clés non-chaînes en chaînes (car la chaîne résultante ne figure pas dans la table, elle devient une clé non valide). Cela se fait plus facilement en passant une copie de la clé au lieu de l'original luaL_checkstring.
  • vous assurer préservez la structure de la pile (à savoir pop autant de valeurs que vous appuyez) sur chaque passage dans la boucle

Votre fonction ne fonctionne que pour les valeurs négatives de index. Vous avez raison que index--; s'assurera que index pointe encore sur la table après avoir appuyé sur la touche, mais seulement si index était négatif (ie par rapport au début de la pile). pour pointer vers le mauvais article. La solution de contournement la plus simple consiste à placer une autre référence sur la table en haut de la pile.

Voici un programme minimal de C à démontrer:

#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' accepte les index négatifs mais il abandonne et donne le mauvais message s'il échoue parce qu'il est censé vérifier les arguments de la fonction, pas pour la conversion générale. – lhf

+0

@lhf, OK, il ne semble pas y avoir d'avantage à utiliser 'luaL_checkstring' à part qu'il se trouvait dans l'exemple de code de la question. Remplacé par 'lua_tostring'. – finnw

-1

Voir aussi l'exemple de la documentation pour lua_next, extrait ici:

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.