--set/getmetatable
{"setmetatable", luaB_setmetatable},
{"getmetatable", luaB_getmetatable},
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or metatable */
}
--debug.set/getmetatable
{"setmetatable", db_setmetatable},
{"getmetatable", db_getmetatable},
static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
lua_settop(L, 2);
lua_pushboolean(L, lua_setmetatable(L, 1));
return 1;
}
static int db_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */
}
return 1;
}
可以看到,两者不同的地方在于,setmetatable 有检测 __metatable 键值,如果存在,setmetatable 会失败。而 getmetatable 会优先返回 __metatable 键值的内容,不存在再返回 metatable。举例说明:
local a = {}
setmetatable(a, {__metatable = "lock"})
print(type(getmetatable(a)), getmetatable(a))
print(type(debug.getmetatable(a)), debug.getmetatable(a))
debug.setmetatable(a, {__metatable = "lock2"})
setmetatable(a, {__metatable = "lock2"})
image.png
网友评论