回顾具有默认值的表
如何实现具有非nil默认值的表。我们将要看到的两种实现这个默认值的技术是对偶表示和记忆这两种通用技术的特例。
第一种解决方案中,我们使用一个弱引用表来映射每一个表和它的默认值:
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
这是对偶表示的一种典型应用,其中使用了defaults[t]来表示t.default.如果表defaults没有弱引用的键,那么具有默认值的表就会永远存在下去。
第二种解决方法中,我们对不同的默认值使用了不同的元表,在遇到重复的默认值时会复用相同的元表。这是记忆技术的一种典型应用:
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
在这种情况下,我们使用弱引用的值是的不再被使用的元表能够被回收。
第一种实现需要为每个具有默认值的表(表defaults中的一个元素)分配几个字节的内存, 而第二种实现则需要为每个不同的默认值分配若干内存(一个新表,一个新闭包和表metas中的一个元素。)因此,如果应用中上千个具有少量不同默认的值,那么第二种实现更为适合,不过如果只有少量默认共享的值,那么就应该选择第一种实现。