元表还可以指定关系操作符的含义,元方法为__eq ,__lt(小于) ,__le(小于等于).
而其它3个关系操作符则没有单独的元方法,Lua会
把a ~= b 转化为not(a == b)
将a>b 转化为 b < a ;
将a>=b 转化为 b <= a ;
因此需要分别为__le和__lt提供实现:
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 mt.__lt = function(a,b) return a<=b and not(b <= a) end
最后,还可以定义集合的相等性判断:
mt.__eq = function(a,b) return a <= b and b<=a end
有了这些定义,可以比较集合了:
s1 = Set.new{2,4} s2 = Set.new{4,10,2} print(s1 <= s2 ) --> true print(s1 < s2) --> true print(s1 >= s1) --> true print(s1 > s1) -->false print(s1 == s2 * s1) -->true
等于比较有一点限制,如果两个对象拥有不同的方法,那么等于操作不会调用任何一个元方法,而是直接返回false。
只有当两个比较对象共享一个元方法时,Lua才调用这个等于比较的元方法。
与算术类的元方法不同的是,关系类的元方法不能应用于混合的类型。
如果试图将一个字符串与一个数字作顺序性比较,Lua会引发一个错误。
库定义的元方法
函数tostring,它能将各种类型的值表示为一种简单的文本格式:
print({}) -->table:0x8062ac0
print函数总是调用tostring来格式化其输出。当格式化任意值时,tostring会检查该值是否有一个__tostring的元方法。
如果有这个元方法,tostring就用该值作为参数来调用这个元方法。
这个元方法工作的结果就是tostring的结果。
在集合的实例中,已定义了一个将集合表示为字符串的函数。接下来要做的就是设置元表中的__tostring字段:
mt.__sostring = Set.tostring
此后只要调用print来打印集合,print就会调用tostring函数,进而调用到Set.tostring:
s1 = Set.new{10,4,5} print(s1) -->{4,5,10}
函数setmetatable和getmetatable也会用到元表中的一个字段,用于保护元表。
假设想要保护集合的元表,使用户既看不到也不能修改集合的元表。那么就需要用到字段__metable。
当设置了该字段,getmetatable就会返回这个字段的值,而setmetatable则会引发一个错误:
mt.__metatable = "not your business" s1 = Set.new{} print(getmetatable(s1)) -->not your business setmetatable(s1,{}) -->stdin:1:cannot change protected metatable
以上内容来自:《Lua程序设计第二版》和《Programming in Lua third edition 》