chapter 13_2 关系类、库定义的元方法

  元表还可以指定关系操作符的含义,元方法为__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.__tostring = 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 》

原文地址:https://www.cnblogs.com/daiker/p/5848349.html