我在这里做一个Ruby教程: http://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/105-equality_of_objects
当我重载==
运算符时,我应该重载eql?
方法和哈希方法,因为它们“更快”。
但是,如果我使用基本相同的方法重载所有三个,那么一个比另一个更快?
答案 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
,它为您定义了体面的==
,hash
和eql?
。
答案 1 :(得分:3)
例如Array#hash
说 -
具有相同内容的两个数组将具有相同的哈希码(并将使用eql进行比较?)。
和Array#==
说:
Equality - 如果两个数组包含相同数量的元素,并且每个元素等于(根据Object#==)other_ary中的相应元素,则它们是相等的。
如果self和other是同一个对象,或者两个数组都具有相同的内容,则返回true。
因此,根据文档,eql?
显然更快,因为它使用hash
值,eql?
。而#==
做了两件事 -
- 数组的长度和
- 每个元素相等测试。
醇>