在Lua table中我们可以访问对应的key来得到value值,但是却无法对两个table直接进行操作。
因此Lua提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。元表就是一种存放了元方法的table,我们可以通过对应的Key来得到value的值,作用就是修改一个值的行为(这就是元方法)。
下面的__add、__index等都是两个两个下划线(“__”)千万注意
如例:
local mytable1 = {1};
local mytable2 = {2};
local mytable3 = mytable1 + mytable2;
如果对两个table直接进行“+”操作,就会报错。
因为程序不知道如何对两个表进行操作,这时候就需要通过元表来定义如何执行“+”操作了
local mt = {}
mt.__add = function(t1,t2)
print("aaa");
end
local mytable1 = {1};
local mytable2 = {2};
mytable1 = setmetatable(mytable1,mt);
local mytable3 = mytable1 + mytable2;
输出结果为:aaa
如果我们为mytable1和mytable2都设置上元表会怎样:
local mt = {}
mt.__add = function(t1,t2)
print("aaa");
end
local mt1 = {};
mt1.__add = function(t1,t2)
print("bbb");
end
local mytable1 = {1};
local mytable2 = {2};
mytable1 = setmetatable(mytable1,mt);
mytable2 = setmetatable(mytable2,mt1);
local mytable3 = mytable1 + mytable2;
结果没有变还是:aaa
但是将mytable1 = setmetatable(mytable1,mt);注释后就是bbb了,所以我们得出他的执行顺序是:
- 查看mytable1是否有元表,若有,则查看mytable1的元表是否有__add元方法,若有则调用。
- 查看mytable2是否有元表,若有,则查看mytabl2的元表是否有__add元方法,若有则调用。
- 完蛋,报错了。
元表中的元方法
来自菜鸟教程的截图
此外还有:
blueberryzzz
上面的加减乘除做法基本类似不做过多的解释。
__index
这是metatable 最常用的键,当访问表中不存的字段 ,会用到这个元方法。__index可以是一个函数也可以是一个table。
函数版:
local mt = {}
mt.__index = function(t,key)
return key;
end
local mytable1 = {};
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
输出:
第一个为nil是自己的表没有指定key的索引,第二个在元表中找到。
table版:
local mt = {}
mt.__index = {key = "hhhh"}
local mytable1 = {};
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
输出:
执行的过程:
- 在表中查找,找到则返回,找不到则继续
- 判断是否有元表,没有返回nil,有则继续
- 判断元表有无__index方法,如果该方法为nil,则返回nil;如果是一个表,则重复1、2、3操作;
__newindex
如果我们给表中不存在的字段赋值的时候,则会调用__newindex。上面我们提到如果在表中查询表中不存在的键时会调用__index,但是给表中不存在的字段赋值时依然不会出现错误。此时会调用__newindex元方法。__newindex可以是一个函数也可以是一个table。
函数版:
__newindex是一个函数时会将赋值语句中的表、索引、赋的值当作参数去调用。不对表进行改变
local mt = {}
mt.__newindex = function (t, key, value)
print("key is ".. key);
print("value is"..value)
end
local mytable1 = {key = "Myvalue"};
--表中key可以输出
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
--为表中不存在的key赋值,会调用元表中的__newindex方法(仅仅是调用元表中的__newindex,不会对本来的表进行改变)
mytable1.newKey = 12;
print(mytable1.newKey);
输出结果:
table版:
__newindex是一个table时,为t中不存在的索引赋值会将该索引和值赋到__newindex所指向的表中,不对原来的表进行改变。
local mt = {}
mt.__newindex = {}
local mytable1 = {key = "Myvalue"};
--表中key可以输出
print(mytable1.key);
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
--为表中不存在的key赋值,会调用元表中的__newindex方法(仅仅是调用元表中的__newindex,不会对本来的表进行改变)
mytable1.newKey = 12;
print(mytable1.newKey);
输出结果:
rawget
rawget可以让你直接获取到表中索引的实际值,而不通过元表的__index元方法。
local mt = {}
mt.__newindex = {}
mt.__index = {key="123"}
local mytable1 = {};
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
print(rawget(mytable1,"key"))
结果:
rawset
rawset可以让你直接为表中索引的赋值,而不通过元表的__newindex元方法。
local mt = {}
mt.__newindex = {}
local mytable1 = {};
mytable1 = setmetatable(mytable1,mt);
print(mytable1.key);
rawset(mytable1,"key","123")
print(mytable1.key);
结果:
__call
__call 元方法在 Lua 调用一个值时调用。
local mt = {}
--__call的第一参数是表自己
mt.__call = function(t,...)
--输出所有参数
for key,value in ipairs{...} do
print(value)
end
end
local mytable1 = {};
setmetatable(mytable1,mt);
mytable1(1,2,3)
__tostring
__tostring 元方法用于修改表的输出行为。
local mt = {}
mt.__tostring = function(t)
local sum = 0;
for key,value in ipairs(t) do
sum = sum + value;
end
return sum;
end
local mytable1 = {1,2,3};
setmetatable(mytable1,mt);
print(mytable1);