2

我在这个网站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 版本中是否发生了变化,还是我的测试出错了?

谢谢你的帮助。

4

1 回答 1

3

这在 Lua 5.3 中发生了变化。自述文件称它为“一些元方法引入了更灵活的规则”。比较Lua 5.2 参考手册

==操作。该函数getequalhandler定义了 Lua 如何为相等性选择元方法。仅当被比较的两个值具有相同类型和所选操作的相同元方法,并且值是表或完整用户数据时,才会选择元方法。

     function getequalhandler (op1, op2)
       if type(op1) ~= type(op2) or
          (type(op1) ~= "table" and type(op1) ~= "userdata") then
         return nil     -- different values
       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   -- primitive equal?
         return true   -- values are equal
       end
       -- try metamethod
       local h = getequalhandler(op1, op2)
       if h then
         return not not h(op1, op2)
       else
         return false
       end
     end

请注意,结果始终是布尔值。

使用Lua 5.3 参考手册

等号 ( ==) 运算。行为类似于加法操作,除了 Lua 仅当被比较的值是两个表或两个完整的用户数据并且它们在原始上不相等时才会尝试元方法。调用的结果始终转换为布尔值。

于 2020-05-22T01:48:58.547 回答