Lua __eq 在拥有不同元表的表中

我在这个网站http://lua-users.org/wiki/MetamethodsTutorial发现了以下引用:

当在两个表上使用==运算符时,引用相等性检查失败,且两个表都具有相同的__eq元方法时,将调用__eq。

现在我使用Lua 5.3.5测试了一下,但这根本不是我观察到的:

a = {}
b = {}
m = {}
m2 = {}
setmetatable(a, m)
setmetatable(b, m2)
m.__eq = function(p1, p2) print("why"); return true end
m2.__eq = function(p1, p2) print("why2"); return true end

这是我测试用的代码。

> a == b
why
true
> b == a
why2
true

它看起来做的事情与比较运算符相同,它只是取左侧表并使用它的元方法。

最近的Lua版本有改动吗,还是我在测试时犯了错误?

感谢你的帮助。

点赞
用户7509065
用户7509065

Lua 5.3 对于一些元方法在 README 文件中做出了更加灵活的规定。与Lua 5.2 参考手册对比,如下:

== 操作。函数 getequalhandler 定义了 Lua 如何选择相等元方法。只有在被比较的值具有相同类型、相同选择操作的元方法,而且这些值必须是表或者全 userdata 类型时,才会选择一个元方法。

     function getequalhandler (op1, op2)
       if type(op1) ~= type(op2) or
          (type(op1) ~= "table" and type(op1) ~= "userdata") then
         return nil     -- 不同的值
       end
       local mm1 = metatable(op1).__eq
       local mm2 = metatable(op2).__eq
       if mm1 == mm2 then return mm1 else return nil end
     end

"eq" 事件的定义如下:

     function eq_event (op1, op2)
       if op1 == op2 then   -- 原始相等?
         return true   -- 值相等
       end
       -- 尝试元方法
       local h = getequalhandler(op1, op2)
       if h then
         return not not h(op1, op2)
       else
         return false
       end
     end

注意结果总是布尔类型。

而在 Lua 5.3 参考手册 中,则有如下规定:

等于 (==) 操作。行为类似于加法操作,只不过当被比较的值都是表或者全 userdata 类型且它们不具有原始相等性时,Lua 才会尝试元方法。调用结果总是被转换为布尔型。

2020-05-22 01:48:58