如何从 Lua C API 获取 lua 设置的元表
How to get metatable set by lua from Lua C API
Lua:
a = {
b = "c",
d = {
e = "f",
g = "h"
}
}
setmetatable(a.d, {__ismt = true})
cfun(a) --call C function to iterate over table a
C:
int cfun(lua_State *L)
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
// iterate over table
lua_pop(L, 1);
}
}
当主机客户端迭代table时,你怎么知道是否有元table?然后你如何获得 metatable?
table是树的形式,需要迭代遍历树。 Lua 已经有一个堆栈实现,所以这使工作更容易。
- 入口处,堆栈顶部有 table,您将压入一个
nil
元素,因为 lua_next()
会在检查 [=43= 之前从堆栈中消耗一个元素].所以堆栈看起来像 table -> nil
.
- 接下来,我们调用
lua_next()
,它将消耗堆栈中的一个元素,并从 table 中添加两个新的键值对。堆栈看起来像 table -> key -> value
。如果没有下一个元素,调用的return值为0。
- 如果 return 值为 1,并且堆栈上的值是嵌套的 table,您将在堆栈上压入 nil,所以现在堆栈看起来像
table -> key -> table -> nil
.现在你几乎就像一开始一样,所以通过循环,你将开始遍历嵌套的 table.
- 如果 return 值是 1,如果值不是 table,到你的值
- 如果 return 值为 0,我们可以检查这是否是元 table。检查完后,你会弹出值并检查堆栈是
table -> key
还是any -> key
。如果栈上的第二个元素不是table,你已经完成遍历,你将打破循环。
这里是实现算法的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;
}
Lua:
a = {
b = "c",
d = {
e = "f",
g = "h"
}
}
setmetatable(a.d, {__ismt = true})
cfun(a) --call C function to iterate over table a
C:
int cfun(lua_State *L)
{
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
// iterate over table
lua_pop(L, 1);
}
}
当主机客户端迭代table时,你怎么知道是否有元table?然后你如何获得 metatable?
table是树的形式,需要迭代遍历树。 Lua 已经有一个堆栈实现,所以这使工作更容易。
- 入口处,堆栈顶部有 table,您将压入一个
nil
元素,因为lua_next()
会在检查 [=43= 之前从堆栈中消耗一个元素].所以堆栈看起来像table -> nil
. - 接下来,我们调用
lua_next()
,它将消耗堆栈中的一个元素,并从 table 中添加两个新的键值对。堆栈看起来像table -> key -> value
。如果没有下一个元素,调用的return值为0。 - 如果 return 值为 1,并且堆栈上的值是嵌套的 table,您将在堆栈上压入 nil,所以现在堆栈看起来像
table -> key -> table -> nil
.现在你几乎就像一开始一样,所以通过循环,你将开始遍历嵌套的 table. - 如果 return 值是 1,如果值不是 table,到你的值
- 如果 return 值为 0,我们可以检查这是否是元 table。检查完后,你会弹出值并检查堆栈是
table -> key
还是any -> key
。如果栈上的第二个元素不是table,你已经完成遍历,你将打破循环。
这里是实现算法的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;
}