如果我使用以下代码:
class Item
attr_reader :item_name, :qty
def initialize(item_name, qty)
@item_name = item_name
@qty = qty
end
def to_s
"Item (#{@item_name}, #{@qty})"
end
def hash
p "hash has been called"
self.item_name.hash ^ self.qty.hash
end
def eql?(other_item)
puts "#eql? invoked"
@item_name == other_item.item_name && @qty == other_item.qty
end
end
p Item.new("abcd", 1).hash
items = [Item.new("abcd", 1), Item.new("abcd", 1), Item.new("abcd", 1)]
p items.uniq
"hash has been called"
4379041107527942435
"hash has been called"
"hash has been called"
#eql? invoked
"hash has been called"
#eql? invoked
"hash has been called"
"hash has been called"
"hash has been called"
[Item (abcd, 1)]
我正在解释这意味着#hash方法被用于为每个对象生成唯一的整数,然后#eql?调用以检查整数是否相等,以检查重复项。我的解释是否正确?
答案 0 :(得分:4)
不,你的解释不正确。
hash
不生成唯一的整数,这正是为什么 eql?
调用是必要的,eql?
是< em> not 在整数上调用,但在元素上调用。
这只是普通的旧哈希,与Hash
,Set
和SortedSet
中使用的完全相同。
hash
是一个哈希函数,即将一个大的(可能是无限的)输入空间映射到一个较小的固定大小的输出空间的函数。由于输出空间小于输入空间,必须必须至少有两个具有相同哈希码的不同对象,因此哈希值不唯一! (这被称为 Pigeonhole Principle 。直观地说:如果你有两个抽屉和三个袜子,那么必须至少有一个抽屉里面至少有两个袜子。)
因为哈希值不是唯一的,所以两个相同的哈希值不会告诉您任何内容。如果两个哈希值不同,那么您知道肯定这两个对象也是不同的。但是如果两个哈希值是相同,那么对象可能仍然不同(这称为 Hash Collision ),这就是为什么你有使用eql?
进行仔细检查。