1、弱表
弱表如何声明呢?通过元表字段__mode来声明,其值必须是字符串,"k"表示关键字是弱的,"v"表示值是弱的,"kv"表示键和值都是弱的。对象才可以收集,数字,布尔,字符串类型的不可以收集。
2、记忆化函数
通过表来记录计算结果,避免下次的重复计算。同时使用弱表来在没有引用时,通过垃圾收集自动处理
local results = {}
setmetatable(results, {__mode = "kv"})
function mem_loadstring(s)
local res = results[s]
if res == nil then
res = assert(load(s))
results[s] = res
end
return res
end
3、弱表实现默认值
local defaults = {}
setmetatable(defaults, {__mode = "k"})
local mt = {__index = function(t) return defaults[t] end}
function setDefault(t, d)
defaults[t] = d
setmetatable(t, mt)
end
不同的默认值使用不同的元表,同时使用记忆化特性
local metas = {}
setmetatable(metas, {__mode = "v"})
function setDefault(t, d)
local mt = metas[d]
if mt == nil then
mt = {__index = function() return d end}
metas[d] = mt
end
setmetatable(t, mt)
end
4、虚表
do
local mem = {}
setmetatable(mem, {__mode = "k"})
function factory(o)
local res = mem[o]
if not res then
res = (function() return o end)
mem[o] = res
end
return res
end
end
因为mem表中的键值对应的是闭包,而闭包又引用键值,导致环。严格的解释器是不会收集key的。
lua中对于表的键值为弱的,而值不是弱的,视为虚表。
5、终结器
lua通过元方法__gc来实现终结器
o = {x = "hi"}
setmetatable(o, {__gc = function(o) print(o.x) end})
o = nil
collectgarbage()
输出为:
hi
如果在设置元表时,没有设置__gc,后面在通过__gc字段设置不起作用。
o = {x = "hi"}
mt = {}
setmetatable(o, mt)
mt.__gc = function(o) print(o.x) end
o = nil
collectgarbage()
输出:
没有输出
在上面情况时,可以先设置元表的标识为true,在设置元表后,再通过字段设置,也是可以的
o = {x = "hi"}
mt = {__gc = true}
setmetatable(o, mt)
mt.__gc = function(o) print(o.x) end
o = nil
collectgarbage()
输出:
hi
在收集相关联对象时,关联关系不会影响收集顺序
以单链表为例
mt = {__gc = function(o) print(o[1]) end}
list = nil
for i = 1, 3 do
list = setmetatable({i, link = list}, mt)
end
list = nil
collectgarbage()
输出为:
3
2
1
当终结器执行时,会将终结的对象作为参数传递给它,此时对象为短暂复活,执行完后,作为永久复活