lua学习笔记---元表(Metatable)

元表的作用在于对于两个表之间的操作,改变table的行为。

1.设置/获取元表

mytable={}

mymetatable={}

mytable=setmetatable(mytable,mymetatable)

将mymetatable设置为mytable的元表。返回值为普通表

mymetatable=getmetatable(mytable)

获取mytable的元表,返回值为元表

2.__index元方法

通过键值访问table时,如果这个键没有值,并且该table存在元表的情况下,会去查找元表中的__index键。如果__index存的是一个方法,就会去执行该方法中的内容。如果是一个表,会访问表中对应键值的值。具体操作流程为:

 例子:

mytable={key1="c#",key2="lua"}
mymetatable={key3="java"}
setmetatable(mytable,mymetatable)
mymetatable.__index=function(table,key)
return "javaScript"
end
print(mytable["key3"])
print(mytable["key4"])

执行以上代码,打印出的结果都是javaScript。虽然mymetatable中本身有key3的值,但访问mytable时,不会去访问mymetatable中原有的键值,当发现table中不存在该键时,才会去访问元表中是否有__index,这里__index中是一个方法,所以会执行方法内容。

  • 1.在表中查找,如果找到,返回该元素,找不到则继续
  • 2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续。
  • 3.判断元表有没有__index方法,如果__index方法为nil,则返回nil;如果__index方法是一个表,则重复1、2、3;如果__index方法是一个函数,则返回该函数的返回值。

同样,如果把上面mymetatable.__index换成一个表,就会去访问该表中的键值元素。例mymetatable.__index={key4="c++"},这时返回的key4就成了c++.

3.__newindex

对table进行赋值操作时,如果有元表,会执行__newindex操作.和index不同之处在于,一个对表的读取,一个对表的赋值。相同处在于都是在普通表中没有该键值时,新键值中的内容都可以是方法或者一个表。

比如上面的方法:

mytable={key1="c#",key2="lua"}
mymetatable={key3="java"}
setmetatable(mytable,mymetatable)
mymetatable.__newindex=function(table,key,value)

print(table,key,value)

end

mytable.key5="c++"

print(mytable.key5)

这里如果没有元表,会直接对mytable赋值,打印出来的是c++.但有元表后会执行__newindex中的方法,不会进行赋值操作,所以打印出来为nil.这里方法和index不同点在于有3个参数,我们可以通过

rawset(tab,key,value)---------lua内置方法,对表赋值

lua中的这个内置函数,对参数进行赋值,效果和mytable.key5="c++"一样。

上面对__newindex是一个方法,如果是一个表的话,会将新的键和值赋给该表,相当于第三个表,这个键值不属于mytable,也不属于它的元表。例:

newtable={}

mymetatable.__newindex=newtable

mytable.key5="c++"

print(mytable.key5,mymetatable.key5,newtable.key5)

得到的结果是只有newtable.key5是c++.当然这里mymetatable.__newindex=mymetatable也是可以的。其实原理就是:

当给table赋值时,如果该键值本身存在,会直接改变原键值元素。如果不存在,会访问元表的_newindex,如果__newindex是一个方法,执行方法。如果是一个表,会将新的键值赋给这个表。

4.__add元方法

lua本身没有对两个表进行合并的方法,直接写table1+table2会报错。可以通过元表中__add键重写操作。下面是例子:


table1={"java","lua","c#"}
table2={"c++","php"}
setmetatable(table1,{
__add=function(tab1,tab2)
mi=#tab1
for k,v in pairs(tab2) do
mi=mi+1
--tab1[mi]=v
table.insert(tab1,mi,v)
end
end
})
table3=table1+table2
for k,v in ipairs(table1) do
print(k,v)
end

这里相当于重写了+的操作,最终得到的结果是table1变成了:

1    java
2    lua
3    c#
4    c++
5    php

这里要注意的一点是,两个相加的表只要其中有一个在元表中定义了add操作,就可以使用+来进行合并表。这里table1+table2改变的是table1,如果改为table2+table1,变的就是table2了。

5__call元方法

__call元方法相当于把表当方法来使用。如果不在元表中对__call键值进行处理的话,是不能直接在表后面加()进行处理的。举个例子,让表中所有元素值加一。例:

mytable={1,2,3,4,5}
setmetatable(mytable,{
__call= function(tab,arg)
for k,v in pairs(tab) do
tab[k]=v+arg
print(tab[k])
end
end
})
mytable(2)

输出的结果是3,4,5,6,7

这里__call中第一个参数是要处理的表,第二个参数才是调用时的第一个参数。

6__tostring元方法

__tostring元方法用于修改表的输出行为,比如这里输出一个表中所有元素的和。

mytable={1,2,3,4,5}

setmetatable(mytable,{
__tostring=function(tab)
local num=0
for k,v in pairs(tab) do
num=num+v
end
return num
end
})
print(mytable)

这里输出的值将不再是表对应的地址,而是这个表中所有元素的和。记得此处既然要输出,要返回一个值。

 

你可能感兴趣的:(unity)