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