关于相等:Lua __eq在具有不同元表的表上

Lua __eq on tables with different metatables

我在此站点上找到了以下报价http://lua-users.org/wiki/MetamethodsTutorial:

__eq is called when the == operator is used on two tables, the reference equality check failed, and both tables have the same __eq metamethod (!).

现在我用Lua 5.3.5对其进行了测试,而这根本不是我观察到的:

1
2
3
4
5
6
7
8
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

这是我测试过的代码。

1
2
3
4
5
6
> a == b
why
true
> b == a
why2
true

它看起来与比较运算符具有相同的功能,在比较运算符中,它仅取左表并使用其元方法。

是在最近的Lua版本中进行了此更改,还是我的测试出错了?

感谢您的帮助。


在Lua 5.3中发生了变化。自述文件说,它引入了"一些元方法更灵活的规则"。比较Lua 5.2参考手册:

the == operation. The function getequalhandler defines how Lua chooses a metamethod for equality. A metamethod is selected only when both values being compared have the same type and the same metamethod for the selected operation, and the values are either tables or full userdata.

1
2
3
4
5
6
7
8
9
     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

The"eq" event is defined as follows:

1
2
3
4
5
6
7
8
9
10
11
12
     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

Note that the result is always a boolean.

使用Lua 5.3参考手册:

the equal (==) operation. Behavior similar to the addition operation, except that Lua will try a metamethod only when the values being compared are either both tables or both full userdata and they are not primitively equal. The result of the call is always converted to a boolean.