2016-08-13 100 views
1

我想查詢某個對象的metatable的名稱。Lua:查詢用戶數據對象的metatable的名稱

想想看,我有些元表註冊爲以下幾點:

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狀態THA 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。

回答

1

好的,現在我明白了。查看https://www.lua.org/source/5.3/lauxlib.c.html#luaL_newmetatable的源代碼,我注意到這種雙重關聯是在metatable中使用「__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; 

} 
+1

的Lua 5.0(這是Lua版本由PIL的免費在線版本覆蓋)確實如您最初提到的雙重關聯。請參閱[這裏](https://www.lua.org/source/5.0/lauxlib.c.html#luaL_newmetatable)。較新的Lua版本不再那樣做了。 – siffiejoe

+0

@siffiejoe謝謝你的信息。 –