第一版是针对 Lua 5.0 编写的。虽然对后续版本仍然有很大参考价值,但还是有一些不同。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目


13.2 – 关系元方法

元表还允许我们通过元方法 __eq相等)、__lt小于)和 __le小于或等于)赋予关系运算符含义。没有针对其他三个关系运算符的单独元方法,因为 Lua 将 a ~= b 转换为 not (a == b),将 a > b 转换为 b < a,将 a >= b 转换为 b <= a

(大括号:在 Lua 4.0 之前,所有顺序运算符都转换为单个运算符,方法是将 a <= b 转换为 not (b < a)。但是,当我们有偏序(即我们类型中的所有元素未正确排序)时,此转换不正确。例如,由于非数字NaN)值,大多数机器中的浮点数并未完全排序。根据目前几乎所有硬件采用的 IEEE 754 标准,NaN 表示未定义的值,例如 0/0 的结果。该标准规定,涉及 NaN 的任何比较都应导致 false。这意味着 NaN <= x 始终为 false,但 x < NaN 也为 false。这意味着从 a <= bnot (b < a) 的转换在这种情况下无效。)

在我们的集合示例中,我们遇到了类似的问题。<= 在集合中一个显而易见(且有用的)含义是集合包含:a <= b 表示 ab 的子集。有了这个含义,a <= bb < a 都有可能是假值;因此,我们需要为 __le小于或等于)和 __lt小于)提供单独的实现

    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
在这些定义之后,我们现在可以比较集合了
    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

与算术元方法不同,关系元方法不支持混合类型。它们对混合类型的行为模仿了 Lua 中这些运算符的常见行为。如果您尝试比较一个字符串和一个数字的顺序,Lua 会引发一个错误。同样,如果您尝试比较两个具有不同元方法的对象的顺序,Lua 会引发一个错误。

相等比较永远不会引发错误,但是如果两个对象具有不同的元方法,相等操作将导致 false,甚至不会调用任何元方法。同样,此行为模仿了 Lua 的常见行为,它总是将字符串归类为与数字不同,无论其值如何。Lua 仅在被比较的两个对象共享此元方法时才会调用相等元方法。