1.元表、元操作
1.1算术元操作
Metatables允许我们改变table的行为,例如,使用Metatables我们可以定义Lua如何计算两个table的相加操作a+b。当Lua试图对两个表进行相加时,他会检查两个表是否有一个表有Metatable,并且检查Metatable是否有__add域。如果找到则调用这个__add函数(所谓的Metamethod)去计算结果。
Lua中的每一个表都有其Metatable。(后面我们将看到userdata也有Metatable),Lua默认创建一个不带metatable的新表
t = {}
print(getmetatable(t)) --> nil
Set.mt = {} -- metatable for sets
function Set.new (t) -- 2nd version --创建
local set = {}
setmetatable(set, Set.mt)
for _, l in ipairs(t) do set[l] = true end
return set
end
function Set.union (a,b) --并集
local res = Set.new{}
for k in pairs(a) do res[k] = true end
for k in pairs(b) do res[k] = true end
return res
end
function Set.intersection (a,b) --交集
local res = Set.new{}
for k in pairs(a) do
res[k] = b[k]
end
return res
end
function Set.tostring (set) --转换
local s = "{"
local sep = ""
for e in pairs(set) do
s = s .. sep .. e
sep = ", "
end
return s .. "}"
end
function Set.print (s) --打印
print(Set.tostring(s))
end
第一步,我们定义一个普通的表,用来作为metatable。为避免污染命名空间,我们将其放在set内部。
Set.mt = {} -- metatable for sets
第二步,给metatable增加__add函数。
Set.mt.__add = Set.union
当Lua试图对两个集合相加时,将调用这个函数,以两个相加的表作为参数。
通过metamethod,我们可以对两个集合进行相加:
s3 = s1 + s2
Set.print(s3) --> {1, 10, 20, 30, 50}
同样的我们可以使用相乘运算符来定义集合的交集操作
Set.mt.__mul = Set.intersection
Set.print((s1 + s2)*s1) --> {10, 20, 30, 50}
Lua选择metamethod的原则:如果第一个参数存在带有__add域的metatable,Lua使用它作为metamethod,和第二个参数无关;
否则第二个参数存在带有__add域的metatable,Lua使用它作为metamethod 否则报错。
1.2关系元操作
Set.mt.__le = function (a,b) -- set containment -- <
for k in pairs(a) do
if not b[k] then return false end
end
return true
end
Set.mt.__lt = function (a,b) -- <=
return a <= b and not (b <= a)
end
Set.mt.__eq = function (a,b) -- ==
return a <= b and b <= a
end
与算术运算的 metamethods 不同,关系元算的 metamethods 不支持混合类型运算。对于混合类型比较运算的处理方法和 Lua 的公共行为类似。