Lua中从表中删除元表

我想要"解钩"表中的元表,并且想知道是否如下所示是正确的方式:

tbl = setmetatable(tbl, false) -- 或者 nil

我找不到任何正确的相关信息。我需要使用赋值运算符吗?

另外,如果元表从未被引用且是匿名的话,这样做是否足以销毁附加到表中的元表?

tbl = setmetatable({}, {__index = something})
-- 后来:
tbl = nil

垃圾收集器是否足以同时删除两个表?

点赞
用户2858170
用户2858170

根据 Lua 参考手册,你在提问前应该先进行参考,setmetatable(tbl, nil) 会删除表 tbl 的元表,除非 tbl 的原始元表受到保护。或者更好地说它不会删除元表,而是删除对它的引用。当然,只要还有其他引用,作为元表的表将不会被删除。

在询问是否可以简单调用函数之前,先自己尝试一下。你可以使用 https://www.lua.org/cgi-bin/demo,或者任何其他 Lua 解释器,在几秒钟内得到答案,而不涉及其他任何人。

运行以下代码:

setmetatable({}, false)

setmetatable({})

将得到以下结果:

input:1: bad argument #2 to 'setmetatable' (nil or table expected)

现在你知道你不能输入 false,你必须明确输入 nil。

为了检查你在参考手册中读到的 \_\_metatable,你可以尝试这段代码:

local tbl = setmetatable({}, {__metatable = true})
setmetatable(tbl, nil)

结果如下:

input:2: cannot change a protected metatable

回答关于你问题的第二个部分:

tbl = nil 不会删除 tbl 引用的表。它只会删除对 tbl 的引用。

local a = {}
local b = a
b = nil
print(a)

a 仍然是一个表。你只是删除其中的一个引用。

一旦没有引用剩下,垃圾收集器就会收集表。

setmetatable(tbl, {}) 将建立一个对表构造器 {} 返回的表的引用,并将该引用存储在 tbl 的内部。

如果 tbl 是该表的最后一个引用,它将在某个时候被收集为垃圾。然后,当然,作为元表的表的唯一引用也将消失,它也将被删除。

如果你这样做:

local a = {}
local b = setmetatable({}, a)

a = nil 不会删除 b 的元表

因此,如果任何一个表剩下的引用都没有了,两个表都将被删除。

2016-09-09 12:36:43