之前提过metatable中的metamathdos触发的条件可以是由lua系统规定(table运算时触发)的,也可以由一些库文件(tostring)指定。
实际上metamathdos的触发,也可以由其他方式达到。
比如说,访问table不存在的域的时候,会查找table的metatable中的__index metamathdos
更新table不存在的域的时候,会查找table的metatable中的__newindex metamathdos
下面来具体介绍以下这两个metamathdos是如何工作的。
访问一个table不存在的域的时候,会查找这个table的metatable中的__index metamathdos。
如果不存在,那么访问的结果就是 nil;
如果存在,返回的结果将由__index给出。
我们来举一个简单的例子:
假设需要一个窗口的table,在创建这个窗口table的时候,希望它能够带有 横坐标,纵坐标,高度,宽度 四个属性的默认值。
目前我们有两种方法。
第一种,就是通过构造器函数,在创建窗口table之后,向它添加这四种属性并添加默认值。
第二种,通过窗口table的metatable的__index域实现。
代码如下:
Set = {}
Set.mt = {}
Set.prototype = {x = 0,y = 0,weight = 100,height = 50}
function DefaultNum(set,v)
local mt={__index = function () return v end}
setmetatable(set,mt)
end
function Set.New(set)
local s = set
setmetatable(s,Set.mt)
return set
end
function Set.index(set,key)
return Set.prototype[key]
end
do
Set.mt.__index = Set.index
local w = Set.New{}
print(w.weight)
end
通过构造器创建了一个空的table,这个table的metatable是Set.mt。
当对w中的weight域进行访问的时候(print(w.weight)),由于w并没有这个域,所以lua去w的metatable中寻找__index metamathdos 。
lua会把table名称和索引值传给__index处理,最后按照__index的返回值来打印。
对table进行更新的时候(通过 table[key] = value 的方式为表增加一个域)。
如果table的metatable中包含__newindex metamathdos,lua会把table名,key,value传给__newindex,由它来处理这次对table的更新。
如果__newindex是一张表,那就会直接更新给这张表。上述两种情况下,lua都不会对table进行更新(不过可以通过__newindex对table更新)。
以下代码对__newindex的特点进行了应用
Set = {}
Set.mt = {}
function Set.New(set)
local s = set
setmetatable(s,Set.mt)
return set
end
function Set.newindex(t,k,v)
Set[k] = v
end
function Set.tostring(t)
local set = "{"
local qes = ""
for k in pairs(t) do
set = set..qes..k
qes = ", "
end
set = set.."}"
return set
end
do
Set.mt.__newindex = Set.newindex
Set.mt.__tostring = Set.tostring
local w = Set.New{}
print(w)
w.z = 10
print(w)
print(Set.z)
Set.mt.__newindex = {}
w.p = 20
print(w)
print(Set.mt.__newindex.p)
end