在之前的笔记中提到当访问一个table中不存在的域的时候,会由__index来处理。
如果需求一个带有默认值的table(访问table不存在的域的时候返回的不是nil),可以通过__index来实现。
代码如下:
local mt = {__index = function(t) return t.__ end}
function Default(t,v)
t.__ = v
setmetatable(t,mt)
end
do
local set = {};
Default(set,10)
print(set[1])
print(set[2])
end
调用Default函数,在table中添加了一个的域,将这张表的默认值存在在其中,将set的metatable设置为mt,在mt中实现了一个__index的域,__index将返回table中的值。
这样实现table的默认值,让拥有同一个metatable的table可以拥有不同的默认值。
可以通过__index,__newindex,来监控访问table的情况。
当访问一个table中不存在的域的时候,lua会访问__index,由它决定下一步动作
当对一个table不存在的域进行赋值的时候,lua会访问__newindex,由它决定下一步动作
所以,要监控所有对table访问的情况,首先要保证table是一张空表,而且还带有__index 和 __newindex
当然,监控一张空table的访问情况是很愚蠢的,我们要做的是,对被监控的table,再其前面设置一个代理的空table,保证可以正常访问其内容又可以监控访问情况。
代码如下:
local t = {1,2,3,4,5,6,7,8,9}
local _t = t
t = {}
local Mt={
__index = function(t,k)
local s = "访问"..k.."元素"
print(s);
return _t[k]
end
,
__newindex = function(t,k,v)
local s = "创建"..k.."="..v
_t[k] = v
end
}
do
setmetatable(t,Mt)
print(t[1])
t[10] = 10
end
将t表中的数据赋值给_t,然后清空t表,让t成为一张空表。
对t访问的时候,会先经过t的metatable,用__index,__newindex 显示对访问的监控。
只读表:
表可以正常被访问,但是不能被修改,有修改表的动作的时候放回错误信息。
如果对table中已经存在的域进行修改,是不会触发__index 和 __newindex,所以还是需要对只读表前方设置一个空的代理table。
这个table的metatable中的__index,指向原来的table,这样可以保证可以正常访问原先的table。
在代理table的metatable的__newindex中处理更新表的动作。
代码如下:
function readonly(t)
local proxy = {}
local mt = {
__index = t ,
__newindex = function() print("read only!") end
}
setmetatable(proxy,mt)
return proxy
end
do
local abc = {1,2,3,4,5,6}
local def = readonly(abc)
print(def[1])
def[1] = 10
end
def作为abc的代理表,在打印def[1]的时候,是可以访问到abc[1]的,但是如果对def[1]进行修改,就会触发mt中的__newindex,然后报错。