13.4.3 有默认值的表

在一个普通的表中任何域的默认值都是nil。很容易通过metatables来改变默认值:

function setDefault (t, d)

    local mt = {__index = function () return d end}

    setmetatable(t, mt)

end

 

tab = {x=10, y=20}

print(tab.x, tab.z)      --> 10   nil

setDefault(tab, 0)

print(tab.x, tab.z)      --> 10   0

现在,不管什么时候我们访问表的缺少的域,他的__index metamethod被调用并返回0setDefault函数为每一个需要默认值的表创建了一个新的metatable。在有很多的表需要默认值的情况下,这可能使得花费的代价变大。然而metatable有一个默认值d和它本身关联,所以函数不能为所有表使用单一的一个metatable。为了避免带有不同默认值的所有的表使用单一的metatable,我们将每个表的默认值,使用一个唯一的域存储在表本身里面。如果我们不担心命名的混乱,我可使用像"___"作为我们的唯一的域:

local mt = {__index = function (t) return t.___ end}

function setDefault (t, d)

    t.___ = d

    setmetatable(t, mt)

end

如果我们担心命名混乱,也很容易保证这个特殊的键值唯一性。我们要做的只是创建一个新表用作键值:

local key = {}    -- unique key

local mt = {__index = function (t) return t[key] end}

function setDefault (t, d)

    t[key] = d

    setmetatable(t, mt)

end

另外一种解决表和默认值关联的方法是使用一个分开的表来处理,在这个特殊的表中索引是表,对应的值为默认值。然而这种方法的正确实现我们需要一种特殊的表:weak table,到目前为止我们还没有介绍这部分内容,将在第17章讨论。

为了带有不同默认值的表可以重用相同的原表,还有一种解决方法是使用memoize metatables,然而这种方法也需要weak tables,所以我们再次不得不等到第17章。


相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛