Lua: 查询userdata对象的metatable名称
Lua: Querying the name of the metatable of a userdata object
我想查询某个对象的元table名称。
考虑到我有一些 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 指出 luaL_newmetatable
进行双重关联,即 它使用名称作为 table 和 table 的键作为名称的键。因此,有了这些知识,我认为我可以实现以下目标:
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 .
好的,我明白了。查看 https://www.lua.org/source/5.3/lauxlib.c.html#luaL_newmetatable 的源代码,我注意到这个双重关联是使用元 table 中的“__name”完成的,而不是使用 table 作为其名称的键在注册表中。此行为以 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;
}
我想查询某个对象的元table名称。
考虑到我有一些 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 指出 luaL_newmetatable
进行双重关联,即 它使用名称作为 table 和 table 的键作为名称的键。因此,有了这些知识,我认为我可以实现以下目标:
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 .
好的,我明白了。查看 https://www.lua.org/source/5.3/lauxlib.c.html#luaL_newmetatable 的源代码,我注意到这个双重关联是使用元 table 中的“__name”完成的,而不是使用 table 作为其名称的键在注册表中。此行为以 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;
}