6

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

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

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

4

2 回答 2

13

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

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

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

做出了一个选择,Hash该类将eql?用来区分不同的键,而不是==. 请注意,它本来可以==,但eql?更干净。

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

因此,hash如果您定义eql?.

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

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

如果您想使用 an 来做同样的事情,则每次查找Array可能需要 10 次调用eql?

对于它的价值,我认为您链接到的 Ruby 入门书并没有尽可能清晰。它忽略了计算 可能很昂贵的事实hash,因此它仅在有意义时才完成,即当每个元素将被比较多次是一个很好的假设时。eql?此外,它提供的自定义示例==用于比较实例变量是一种耻辱。理想情况下,它将eql?用于一致性,就像数组是,==如果它的元素是==,数组是,eql?如果它的元素是eql?。最后,它真的应该提到Struct哪个定义了体面==hash并且eql?为您定义。

于 2013-04-24T21:46:19.507 回答
3

例如Array#hash说 -

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

Array#==说:

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

Array#eql?

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

因此,根据文档,很明显eql?它使用hashvalue 会更快,使用eql?. 而#==做两件事 -

  1. 数组的长度和
  2. 每个元素相等性测试。
于 2013-04-24T21:19:27.480 回答