Lua 中关于设置 __gc 顺序的问题

有人能告诉我为什么 code1 和 code2 有不同的结果,但 code3 和 code4 的结果相同吗?

code1:

o = {x = "hi"}
mt = {}
mt.__gc = function (o) print(o.x) end
setmetatable(o, mt)
o = nil
collectgarbage()

code1 的结果:

hi

code2:

o = {x = "hi"}
mt = {}
setmetatable(o, mt)
mt.__gc = function (o) print(o.x) end
o = nil
collectgarbage()

code2 的结果: 什么也没输出

code1 和 code2 的唯一区别是执行了语句 setmetatable(o, mt)mt.__gc = function (o) print(o.x) end 的顺序不同。它们的结果完全不同:第一个打印了 hi 而另一个什么也没有打印。设置元表的顺序最终会影响到结果吗?如果会,为什么 code3 和 code4 的结果相同?

code3:

o = {x = "hi"}
mt = {}
setmetatable(o, mt)
mt.__index = function () print("没有这个键") end
print(o["x"])
print(o["y"])

code4:

o = {x = "hi"}
mt = {}
mt.__index = function () print("没有这个键") end
setmetatable(o, mt)
print(o["x"])
print(o["y"])

code3 和 code4 的结果都相同:

hi

没有这个键

nil

点赞
用户6632736
用户6632736

自 Lua 5.2 版本开始,Lua 表格支持元方法 __gc。引用第二段:

对于一个要在回收时进行最终操作的对象(表格或用户数据),你必须标记它进行最终操作。当你设置其元表并且元表有一个被字符串 " __gc" 索引的字段时,你就可以将对象标记为最终操作。请注意,如果你设置一个没有 __gc 字段的元表,然后后来在元表中创建该字段,该对象不会被标记为最终操作。

这正是你的情况:第二句描述了第一个例子,第三句描述了第二个例子。

2020-10-05 12:37:13