比较Ruby中的对象等价

时间:2013-04-24 21:14:54

标签: ruby

我在这里做一个Ruby教程: http://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/105-equality_of_objects

当我重载==运算符时,我应该重载eql?方法和哈希方法,因为它们“更快”。

但是,如果我使用基本相同的方法重载所有三个,那么一个比另一个更快?

2 个答案:

答案 0 :(得分:13)

在大多数情况下,==eql?的结果相同。在某些情况下,eql?==更严格:

42.0 == 42 # => true
42.0.eql?(42) # => false

因此,如果您定义==,您可能也想定义eql?(反之亦然)。

选择Hash类会使用eql?来区分不同的密钥,而不是==。它可能是==,请注意,eql?更清洁。

为避免对eql?进行昂贵的调用,计算哈希值时要求两个eql?对象必须具有相同的哈希值。存储该哈希值,这使得将来的查找非常容易:如果哈希码不匹配,则值不是eql? ...

因此,如果您定义hash,则必须以合理的方式定义eql?

请注意,计算哈希值几乎总是比与==eql?进行比较更昂贵。但是,一旦计算了哈希值,检查哈希值是否匹配就非常快。

因为散列通常涉及很多比较,所以对每个键进行一次相对昂贵的散列计算,然后对每次查找执行一次。想象一下有10个条目的哈希。在第一次查找完成之前,构建它将涉及对hash的10次调用。第一次查找会相对较快:一次调用hash,然后非常有效地比较哈希码(它实际上比这更快,因为它们被“索引”)。如果匹配,则必须仍然拨打eql?来确保它是真正的匹配。实际上,两个不是eql?的对象可能具有相同的哈希值。唯一的保证是两个eql?对象必须具有相同的哈希值,但两个不同的对象也可以具有相同的哈希值。

如果您想使用Array进行相同操作,则每次查询可能需要10次调用eql?

对于它的价值,我不认为你链接到的Ruby引物尽可能清晰。它忽略了这样一个事实:计算hash可能是昂贵的,所以只有在它有意义时才会这样做,即当一个好的假设是每个元素将被多次比较时。此外,遗憾的是,自定义eql?的示例使用==来比较实例变量。理想情况下,它会使用eql?来保持一致性,就像数组为==时一样,如果其元素为==,则数组为eql?,如果其元素为eql? }。最后,它确实应该提到Struct,它为您定义了体面的==hasheql?

答案 1 :(得分:3)

例如Array#hash说 -

  

具有相同内容的两个数组将具有相同的哈希码(并将使用eql进行比较?)。

Array#==说:

  

Equality - 如果两个数组包含相同数量的元素,并且每个元素等于(根据Object#==)other_ary中的相应元素,则它们是相等的。

Array#eql?

  

如果self和other是同一个对象,或者两个数组都具有相同的内容,则返回true。

因此,根据文档,eql?显然更快,因为它使用hash值,eql?。而#==做了两件事 -

  
      
  1. 数组的长度和
  2.   
  3. 每个元素相等测试。
  4.