Ruby的Array如何比较元素的相等性?

6

以下是一些示例代码:

class Obj
  attr :c, true

  def == that
    p '=='
    that.c == self.c
  end
  def <=> that
    p '<=>'
    that.c <=> self.c
  end
  def equal? that
    p 'equal?'
    that.c.equal? self.c
  end
  def eql? that
    p 'eql?'
    that.c.eql? self.c
  end
end

a = Obj.new
b = Obj.new

a.c = 1
b.c = 1

p [a] | [b]

它打印了2个对象,但应该只打印1个对象。没有任何比较方法被调用。Array.|如何进行相等比较?

3个回答

6

Array#| 是使用哈希实现的。因此,为了让您的类型与其(以及哈希图和哈希集)配合良好,您需要实现eql?(已完成)和hash(未完成)。定义有意义的哈希最直接的方法是返回c.hash


只是确认一下 - Ruby的Array#hash方法是否保证只有在数组内容相等时,值才会相等? - Eric Walker
@EricWalker 不是的。如果(但不仅限于)两个数组都包含按相同顺序具有相同哈希值的元素,则保证两个数组的哈希值相等。然而,这与本问题无关,因为在此哈希仅在元素上调用,而从未在数组本身上调用。 - sepp2k

1

Ruby的Array类是用C实现的,据我所知,在使用|比较对象时,它使用自定义哈希表来检查相等性。如果您想修改此行为,则必须编写自己的版本,该版本使用您选择的相等性检查。

要查看Ruby的Array#|的完整实现:点击此处并搜索“rb_ary_or(VALUE ary1, VALUE ary2)


0

Ruby正在调用哈希函数并返回不同的值,因为它们仍然只返回默认的object_id。您需要def hash并返回反映您对使Obj重要的内容的想法。

>> class Obj2 < Obj
>>   def hash; t = super; p ['hash: ', t]; t; end
>> end
=> nil
>> x, y, x.c, y.c = Obj2.new, Obj2.new, 1, 1
=> [#<Obj2:0x100302568 @c=1>, #<Obj2:0x100302540 @c=1>, 1, 1]
>> p [x] | [y]
["hash: ", 2149061300]
["hash: ", 2149061280]
["hash: ", 2149061300]
["hash: ", 2149061280]
[#<Obj2:0x100302568 @c=1>, #<Obj2:0x100302540 @c=1>]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接