我正在尝试正确实现一些自定义类,以便在集合中使用它们。自定义类B包含一个包含类A对象的数组实例变量。这是一个MWE:
#!/usr/bin/env ruby
require 'set'
class A
attr_reader :a
def initialize(a)
@a = a
end
def hash
@a.hash
end
def eql?(other)
@a == other.a
end
end
class B
attr_reader :instances
def initialize
@instances = Array.new
end
def add(i)
@instances.push(i)
end
def hash
@instances.hash
end
def eql?(other)
@instances == other.instances
#@instances.eql?(other.instances)
end
end
s = Set.new
b1 = B.new
b1.add(A.new(4))
b1.add(A.new(5))
b2 = B.new
b2.add(A.new(4))
b2.add(A.new(5))
s.add(b1)
s.add(b1)
s.add(b2)
puts s.size
输出为2
,预期为1
,因为b1
和b2
是使用相同值构建的对象。
如果我在B类的eql?
实现中使用==
而不是eql?
,那么输出是正确的。根据{{3}}中==
的定义,==
的使用不应该在这里正确吗?我理解这个错误在哪里?
答案 0 :(得分:1)
TL; DR因为:
Array#==
通过==
Array#eql?
通过eql?
根据ruby文档中
==
的定义,==
的使用不应该在这里正确吗?
如果您通过Array#==
比较数组,相应的项目也会通过==
进行比较:(强调添加)
如果两个数组包含相同数量的元素并且每个元素等于(根据Object#== )
,则它们是相等的
示例:
[A.new(4)] == [A.new(4)]
#=> false
它失败,因为元素根据==
不相等:
A.new(4) == A.new(4)
#=> false
如果我在类
eql?
中==
的实现中使用eql?
而不是B
,那么输出就是正确的。
Array#eql?
有效,因为它会通过eql?
比较相应的项目:(强调添加)
如果self和other是同一个对象,或者两个数组都具有相同的内容(根据Object#eql?),则返回
true
。
示例:
[A.new(4)].eql? [A.new(4)]
#=> true
因为:
A.new(4).eql? A.new(4)
#=> true
为了让==
正常工作,您必须实施A#==
:
class A
# ...
def eql?(other)
@a == other.a
end
alias_method :==, :eql?
end
A.new(4) == A.new(4) #=> true
[A.new(4)] == [A.new(4)] #=> true