简体   繁体   中英

Removing Metatables from a table in Lua

I want to "unhook" a metatable from a table and was wondering if:

tbl = setmetatable(tbl, false) -- or nil

is the correct way to do this? I could not find any info about how to do it correctly. Do I need to use an assignment operator?

Also, would this be enough to destroy the metatable attached to the table if the metatable never had a reference and was anonymous?:

tbl = setmetatable({}, {__index = something})
-- later on:
tbl = nil

and the garbage collector would be enough to remove both tables?

According to the Lua reference, which you should always consult befor putting up a question here, setmetatable(tbl, nil) will delete the metatable of table tbl unless tbl's original metatable is protected. Or let's better say it does not delete the metatable but the reference to it. The table that served as metatable will of course not be deleted as long as there are other references to it.

Befor you ask people if a simple function call works, try it yourself. You can use https://www.lua.org/cgi-bin/demo or any other Lua interpreter and you get your answer in seconds without involving anyone else.

Running this code:

setmetatable({}, false)

or

setmetatable({})

will result in

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

Now you know that you cannot enter false and you have to enter nil explicitly.

To checkout that __metatable thing you would have read in the reference manual you could then try this code

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

Which results in the following output:

input:2: cannot change a protected metatable

To the second part of your question:

tbl = nil will not delte the table referenced by tbl. It will only remove the reference tbl to it.

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

a is still a table. You only removed one of its references.

Once there is no reference left the garbage collector may collect the table.

setmetatable(tbl, {}) will establish a reference to the table returned by the table constructor {} and store that reference somewhere in the guts of tbl .

If tbl was the last reference to that table it will be collected as garbage at some point. Then of course the only reference to the table you set as metatable will also be gone and it will removed as well.

If you do something like that:

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

, a = nil will not delete b's metatable

So yes it will remove both tables if no other reference to either one of them is left.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM