Таблица представляет собой дерево, и вам нужно пройти по дереву в итеративном режиме. В Lua уже есть реализация стека, так что это упрощает работу.
- При входе стек имеет таблицу наверху, вы поместите элемент
nil
, так как lua_next()
будет потреблять один элемент из стека перед проверкой таблицы. Таким образом, стек будет выглядеть как table -> nil
.
- Затем мы вызываем
lua_next()
, который использует один элемент из стека и добавит две новые пары ключ-значение из таблицы. Стек будет выглядеть как table -> key -> value
. Если следующего элемента нет, возвращаемое значение вызова равно 0.
- Если возвращаемое значение равно 1, а значение в стеке является вложенной таблицей, вы поместите nil в стек, поэтому теперь стек будет выглядеть как
table -> key -> table -> nil
. Теперь вы почти как в начале, поэтому с циклом вы начнете обход вложенной таблицы.
- если возвращаемое значение равно 1, и если значение не является таблицей, к вашим материалам со значением
- если возвращаемое значение равно 0, мы можем проверить, была ли это метатаблица. После проверки вы извлечете значение и проверите, является ли стек
table -> key
или any -> key
. Если второй элемент в стеке не является таблицей, вы завершили обход и разорвали цикл.
Вот код C
, реализующий алгоритм. Я оставил printf
, чтобы помочь в отладке. printf()
следует удалить.
static int cfun(lua_State *L)
{
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushnil(L); // Add extra space for the first lua_next to pop
int loop=1;
do {
if ( lua_next(L,-2) != 0 ) {
if (lua_istable(L,-1)) {
printf("Table [%s] \n", lua_tostring(L, -2));
lua_pushnil(L); // Start iterating this sub-table
} else {
// The Key and Value are on the stack. We can get their type
printf("(%s - %s)\n",
lua_tostring(L, -2),
lua_typename(L, lua_type(L, -1)));
lua_pop(L,1);
}
} else {
printf("table finished, still on stack (%s -> %s -> %s)\n",
lua_typename(L, lua_type(L, -3)),
lua_typename(L, lua_type(L, -2)),
lua_typename(L, lua_type(L, -1)));
if (lua_getmetatable(L,-1)) {
// The table has metatable. Now the metatable is on stack
printf("Metatable detected\n");
lua_pop(L,1); // remove the metatable from stack
}
lua_pop(L,1); // Pop the current table from stack
if (!lua_istable(L, -2)) {
loop = 0; // No more tables on stack, breaking the loop
}
}
} while (loop);
lua_pop(L,1); // Clear the last element
lua_pushnumber(L,0); // Return 0
return 1;
}
person
jordanvrtanoski
schedule
17.03.2021
lua_getmetatable
? - person Joseph Sible-Reinstate Monica   schedule 16.03.2021