开发者

How does Ruby's Array.| compare elements for equality?

Here's some example code:

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开发者_JAVA技巧
b.c = 1

p [a] | [b]

It prints 2 objects but it should print 1 object. None of the comparison methods get called. How is Array.| comparing for equality?


Array#| is implemented using hashs. So in order for your type to work well with it (as well as with hashmaps and hashsets), you'll have to implement eql? (which you did) and hash (which you did not). The most straight forward way to define hash meaningfully would be to just return c.hash.


Ruby's Array class is implemented in C, and from what I can tell, uses a custom hash table to check for equality when comparing objects in |. If you wanted to modify this behavior, you'd have to write your own version that uses an equality check of your choice.

To see the full implementation of Ruby's Array#|: click here and search for "rb_ary_or(VALUE ary1, VALUE ary2)"


Ruby is calling the hash functions and they are returning different values, because they are still just returning the default object_id. You will need to def hash and return something reflecting your idea of what makes an Obj significant.

>> 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>]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜