【问题标题】:Lua: Querying the name of the metatable of a userdata objectLua:查询用户数据对象的元表名称
【发布时间】:2016-08-13 19:56:46
【问题描述】:

我想查询某个对象的元表名。

考虑我有一些元表注册如下:

Object obj; // some C object

luaL_newmetatable(lua, "my_metatable"); // it's empty

lua_pushlightuserdata(lua, &obj);
luaL_setmetatable(lua, "my_metatable");
lua_setglobal(lua, "obj_");

文档here 声明luaL_newmetatable 进行双重关联,即它使用名称作为表的键,而表作为名称的键。因此,有了这些知识,我认为我可以实现以下目标:

int getMTName(lua_State *L)
{
    lua_getmetatable(L, 1); // get the metatable of the object
    lua_rawget(L, LUA_REGISTRYINDEX); // since the metatable is a key
                                      // to its name in registry, use 
                                      // it for querying the name
    return 1; // the bottom of the stack is now the name of metatable
}

并像这样注册它:

lua_pushcfunction(lua, getMTName);
lua_setglobal(lua, "getMTName");

但是,不幸的是,它不起作用,它返回了nil。那么,我有什么不好呢?

这里是一些完整的源代码(C++):

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#include <iostream>

struct Object {
    int x;
};

int getMTName(lua_State *L)
{
    lua_getmetatable(L, 1);
    lua_rawget(L, LUA_REGISTRYINDEX);
    return 1;
}

int main(int argc, char **argv)
{

    lua_State *L =luaL_newstate();
    luaL_openlibs(L);

    Object obj;

    lua_pushcfunction(L, getMTName);
    lua_setglobal(L, "getMTName");

    luaL_newmetatable(L, "my_metatable");

    lua_pushlightuserdata(L, &obj);
    luaL_setmetatable(L, "my_metatable");
    lua_setglobal(L, "obj_");

    int e = luaL_dostring(L, "print(getMTName(obj_))");

    if (e)
    {
        std::cerr << "ERR: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);
    }

    return 0;

}

输出为nil。我的 Lua 版本是 5.3。

【问题讨论】:

    标签: c lua metatable


    【解决方案1】:

    好的,现在我明白了。查看https://www.lua.org/source/5.3/lauxlib.c.html#luaL_newmetatable 的源代码,我注意到这种双重关联是使用元表中的“__name”完成的,而不是使用表作为注册表中其名称的键。此行为从 Lua 5.3 开始。

    示例代码:

    extern "C"
    {
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
    }
    
    #include <iostream>
    
    struct Object {
        int x;
    };
    
    int getMTName(lua_State *L)
    {
        lua_getmetatable(L, 1);
        lua_pushstring(L, "__name");
        lua_rawget(L, 2);
        return 1;
    }
    
    int main(int argc, char **argv)
    {
    
        lua_State *L =luaL_newstate();
        luaL_openlibs(L);
    
        Object obj;
    
        lua_pushcfunction(L, getMTName);
        lua_setglobal(L, "getMTName");
    
        luaL_newmetatable(L, "my_metatable");
    
        lua_pushlightuserdata(L, &obj);
        luaL_setmetatable(L, "my_metatable");
        lua_setglobal(L, "obj_");
    
        int e = luaL_dostring(L, "print(getMTName(obj_))");
    
        if (e)
        {
            std::cerr << "ERR: " << lua_tostring(L, -1) << std::endl;
            lua_pop(L, 1);
        }
    
        return 0;
    
    }
    

    【讨论】:

    • Lua 5.0(这是 PIL 的免费在线版本所涵盖的 Lua 版本)执行您最初提到的双重关联。见here。较新的 Lua 版本不再那样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 2020-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    相关资源
    最近更新 更多