元表元方法 lua中每个值都可以拥有元表(但不一定有)。元表也是普通表,只是用来记录数据在某些特定条件下的操作行为。如: 对表进行相加操作时,lua会判断是否存在__add
的元方法,并对其进行调用。可以通过setmetatable(table,metatable)
的方式设置元表。通过getmetatable(table)
获取元表。
1 2 3 4 5 6 7 8 9 t1, t2 = {num = 1 }, {num = 2 } mt = { __add = function (a, b) return {num = a.num + b.num} end } setmetatable (t1, mt)setmetatable (t2, mt)t3 = t1 + t2 print ("result = " ..t3.num)
数学计算相关部分元方法的key如下:
1 2 3 4 __add: +(加) __sub: -(减) __mul: x(乘) __div: ÷(除) __mod: %(取余) __unm: -(相反数) __concat: ..(连接) __eq: ==(相等) __lt: <(小于) __le: >(大于) __pow: ^(乘幂)
注意
如果两个表具有相同的元方法,那在执行此计算时没有问题。
如果两个表具有不同的元方法:
第一个值有元表,以第一个为准
第一个没,第二个有元表,以第二个为准
都没有:无法计算,报错
一些特殊的元方法 __tostring 用来修改表的输出行为。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 t = {200 ,300 ,400 } setmetatable (t, {__tostring = function (table) local result = "" for k,v in pairs (table ) do result = result .. k .. " : " .. v.."\n" end return result end })print (t)
__index –>用于查询访问<– 。当通过key
访问表中数据时,如果表中这个key是没有值的,那么在__index
元方法存在时就会访问元方法。
如果__index
元方法是一张表。就会从这张表中取数据
1 2 3 4 5 6 7 t = {name = "tom" } setmetatable (t, {__index = { name = "default" , age = 0 }})print (t.name)print (t.age)
如果__index
元方法是一个function。那么就会调用此方法。
1 2 3 4 5 6 7 8 t = {} setmetatable (t, {__index = function (table, key) print ("表中不存在key:" ..key) end })print (t.count)
__newindex –>用于更新修改<– 。当对一个当前不存在的key赋值时,如果存在__newindex
元方法,会调用此元方法而不是直接赋值。同样__newindex
可以是方法也可以是一个表。
1 2 3 4 5 6 7 8 9 10 11 t = {k1 = "Tom" } setmetatable (t, {__newindex = function (_table, k, v) print ("请不要尝试给" ..k.."赋值" ) end })print (t.k1)t.k2 = "Kitty" print (t.k2)
如果是表。添加的数据会添加在元方法的表中(如下的mt中),而不是t中。
1 2 3 4 5 6 7 8 9 10 11 t = {k1 = "Tom" } mt = {} setmetatable (t, {__newindex = mt})print (t.k1)t.k2 = "Kitty" print (t.k2)print (mt.k2)
忽略元表 当我们需要忽略__index
和__newindex
时。
可以通过rawget
函数忽略__index元方法,存粹的调用表中的值。使用rawset
函数忽略__newindex元方法,纯粹的给表赋值。
1 2 3 4 5 6 7 8 9 10 11 t = {name = "Tom" } mt1 = {age = 0 } mt2 = function (t, k, v) print ("不许赋值!" ) end setmetatable (t, {__index = mt1 ,__newindex = mt2})print (rawget (t, "age" ))rawset (t, "age" , 999 )print (t.age)
一个出自网络的例子 1 2 3 4 5 6 7 8 9 10 11 12 13 local smartMan={name="none" }local other = {name = "大家好" } local t1={}local mt = { __index = smartMan, __newindex = other} setmetatable (t1, mt); print ("other的名字,赋值前:" .. other.name); t1.name = "小偷" ; print ("other的名字,赋值后:" .. other.name); print ("t1的名字:" .. t1.name);
__call 把表当作方法调用时会被调用。
1 2 3 4 5 6 7 t = {} setmetatable (t, {__call = function (self, data) return "hello " ..data end })print (t("jobs" ))