Lua关联对象属性及带有非nil默认值的表(弱引用相关)

关联对象属性

weak tables 的另一个重要的应用就是和对象的属性关联。在一个对象上加入更多的属性是无时无刻都会发生的: 函数名称,tables 的缺省值,数组的大小,等等。

当对象是表的时候,我们可以使用一个合适的唯一 key 来将属性保存在表中。就像我们在前面说的那样,一个很简单并且可以防止错误的方法是建立一个新的对象(典型的比如 table)然后把它当成 key 使用。然而,如果对象不是 table,它就不能自己保存自身的属性。即使是 tables,有些时候我们可能也不想把属性保存在原来的对象中去。例如,我们可能希望将属性作为私有的,或者我们不想在访问 table 中元素的时候受到这个额外的属性的干扰。在上述这些情况下,我们需要一个替代的方法来将属性和对象联系起来。当然,一个外部的 table 提供了一种理想化的方式来联系属性和对象(tables 有时被称作联合数组并不偶然)。我们把这个对象当作 key 来使用,他们的属性作为 vaule。

一个外部的 table 可以保存任何类型对象的属性(就像 Lua 允许我们将任何对象看作key)。此外,保存在一个外部 table 的属性不会妨碍到其他的对象,并且可以像这个 table本身一样私有化。

然而,这个看起来完美的解决方案有一个巨大的缺点:一旦我们在一个 table 中将一个对象使用为 key,我们就将这个对象锁定为永久存在。Lua 不能收集一个正在被当作key 使用的对象。如果我们使用一个普通的 table 来关联函数和名字,那么所有的这些函数将永远不会被收集。

正如你所想的那样,我们可以通过使用 weak table 来解决这个问题。这一次,我们需要 weak keys。一旦没有其他地方的引用,weak keys 并不会阻止任何的 key 被收集。从另一方面说,这个 table 不会存在 weak vaules;否则,活动对象的属性就可能被收集了。

Lua 本身使用这种技术来保存数组的大小。像我们下面即将看到的那样,table 库提供了一个函数来设定数组的大小,另一个函数来读取数组的大小。当你设定了一个数组的大小,Lua 将这个尺寸保存在一个私有的 weak table,索引就是数组本身,而 value 就是它的尺寸。

重述带有默认值的表

在章节 13.4.3,我们讨论了怎样使用非 nil 的默认值来实现表。我们提到一种特殊的技术并注释说另外两种技术需要使用 weak tables,所以我们推迟在这里介绍他们。现在,介绍她们的时候了。就像我们说的那样,这两种默认值的技术实际上来源于我们前面提到的两种通用的技术的特殊应用:对象属性和记忆。

在第一种解决方案中,我们使用 weak table 来将默认 vaules 和每一个 table 相联系:

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

如果默认值没有 weak 的 keys,它就会将所有的带有默认值的 tables 设定为永久存在。在第二种方法中,我们使用不同的 metatables 来保存不同的默认值,但当我们重复使用一个默认值的时候,重用同一个相同的 metatable。这是一个典型的记忆技术的应用:

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 -- memoize
end
 setmetatable(t, mt)
end

这种情况下,我们使用 weak vaules,允许将不会被使用的 metatables 可以被回收。把这两种方法放在一起,哪个更好?通常,取决于具体情况。它们都有相似的复杂性和相似的性能。

第一种方法需要在每个默认值的 tables 中添加一些文字(一个默认的入口)。
第二种方法需要在每个不同的默认值加入一些文字(一个新的表,一个新的闭包,metas 中新增入口)。

所以,如果你的程序有数千个 tables,而这些表只有很少数带有不同默认值的,第二种方法显然更优秀。另一方面,如果只有很少的 tables 可以共享相同的默认 vaules,那么你还是用第一种方法吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值