如何从 Lua C API 获取由 lua 设置的元表

Posted

技术标签:

【中文标题】如何从 Lua C API 获取由 lua 设置的元表【英文标题】:How to get metatable set by lua from Lua C API 【发布时间】:2021-06-13 19:25:39 【问题描述】:

卢阿:

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

当主机客户端迭代表时,您如何知道是否存在元表?那么你如何获得元表呢?

【问题讨论】:

lua_getmetatable? 【参考方案1】:

表是树的形式,需要以迭代的方式遍历树。 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 代码。为了帮助调试,我离开了printfprintf() 应该被删除。

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 C API 获取由 lua 设置的元表的主要内容,如果未能解决你的问题,请参考以下文章

Lua - 如何传递一个 API 调用获得的字符串来调用另一个 API 调用

Lua_C_API

如何使用 C API 创建嵌套 Lua 表

从Lua调用C

如何在lua中设置文件写入函数调用的长度?

如何在 Lua 上使用 Win API 获取硬盘的序列号