编辑:另请参阅对在 C API中实现有特殊警告的任何人的答案。__eq
__eq
元方法属于您的元表,而不是表__index
。
在 lua 中:
function my_equal(x,y)
return x.value == y.value
end
A = {} -- luaL_newmetatable(lua, "A");
A.__eq = my_equal
function new_A(value)
local a = { value = value }
return setmetatable(a, A)
end
B = {} -- luaL_newmetatable(lua, "B");
B.__eq = my_equal
function new_B(value)
local b = { value = value }
return setmetatable(b, B)
end
a = new_A()
b = new_B()
print(a == b) -- __eq is called, result is true
a.value = 5
print(a == b) -- __eq is called, result is false
你所做的是这样的:
myLib_A = {}
myLib_A.__eq = my_equal
A = {} -- luaL_newmetatable(lua, "A");
A.__index = myLib_A
请注意,__eq
它不在A 的元表中,它在一个完全独立的表上,您只是碰巧在不同的、不相关的元方法 ( __index
) 中使用它。Lua 在尝试解析相等运算符时不会查看a
.
Lua 手册详细解释了这一点:
“eq”:== 操作。函数 getcomphandler 定义 Lua 如何为比较运算符选择元方法。仅当被比较的两个对象具有相同类型和所选操作的相同元方法时,才会选择元方法。
function getcomphandler (op1, op2, event)
if type(op1) ~= type(op2) then return nil end
local mm1 = metatable(op1)[event]
local mm2 = metatable(op2)[event]
if mm1 == mm2 then return mm1 else return nil end
end
“eq”事件定义如下:
function eq_event (op1, op2)
if type(op1) ~= type(op2) then -- different types?
return false -- different objects
end
if op1 == op2 then -- primitive equal?
return true -- objects are equal
end
-- try metamethod
local h = getcomphandler(op1, op2, "__eq")
if h then
return (h(op1, op2))
else
return false
end
end
所以当 Lua 遇到 时result = a == b
,它将执行以下操作(这是在 C 中完成的,这里使用 Lua 作为伪代码):
-- Are the operands are the same type? In our case they are both tables:
if type(a) ~= type(b) then
return false
end
-- Are the operands the same object? This comparison is done in C code, so
-- it's not going to reinvoke the equality operator.
if a ~= b then
return false
end
-- Do the operands have the same `__eq` metamethod?
local mm1 = getmetatable(a).__eq
local mm2 = getmetatable(b).__eq
if mm1 ~= mm2 then
return false
end
-- Call the `__eq` metamethod for the left operand (same as the right, doesn't really matter)
return mm1(a,b)
您可以看到这里没有导致 resolve 的路径a.__eq
,这将myLib_A
通过您的元方法解决__index
。