【发布时间】:2021-06-01 04:05:14
【问题描述】:
所以,我正在尝试修补一个类以允许它用于哈希键。但是,我似乎无法让它工作。这是一个示例测试用例:
class Tmp
def hash; rand(); end
end
module Patch
refine Tmp do
def hash; 1; end
def eql?(rhs); hash == rhs.hash; end
end
end
puts "=========================="
module A
# Using the initial implementation of Tmp
x = {}
x[Tmp.new] = 1
x[Tmp.new] = 2
puts "#{Tmp.new.hash == Tmp.new.hash}"
puts "#{Tmp.new.eql? Tmp.new}"
puts "#{x}"
end
puts "=========================="
module A
# Enabling the refinement of class Tmp here
using Patch
x = {}
x[Tmp.new] = 1
x[Tmp.new] = 2
puts "#{Tmp.new.hash == Tmp.new.hash}"
puts "#{Tmp.new.eql? Tmp.new}"
puts "#{x}"
end
这给出了结果:
==========================
false
false
{#<Tmp:0x0000407e4ae818>=>1, #<Tmp:0x0000407e4ae7a0>=>2}
==========================
true
true
{#<Tmp:0x0000407e4ae188>=>1, #<Tmp:0x0000407e4ae110>=>2}
如您所见,#eql? 和 #hash 方法按预期工作,但是当我尝试将其用作哈希键时,它认为它们是不同的键。我做错了什么?
编辑
顺便说一句,docs 状态:
两个对象引用相同的哈希键当它们的哈希值相同时并且这两个对象是eql?彼此。
如果 hash 和 eql?方法被覆盖以提供有意义的行为。
(强调我的)
有趣的是,似乎只有#eql? 用于确定密钥相等性:
class Tmp
def hash; rand; end
def eql?(rhs); true; end
end
puts "=========================="
module A
x = {}
x[Tmp.new] = 1
x[Tmp.new] = 2
puts "#{Tmp.new.hash == Tmp.new.hash}"
puts "#{Tmp.new.eql? Tmp.new}"
puts "#{x}"
end
给予:
==========================
false
true
{#<Tmp:0x0000407e407b08>=>2}
#hash 的返回值不相关:
class Tmp
def hash; 1; end
def eql?(rhs); false; end
end
puts "=========================="
module A
x = {}
x[Tmp.new] = 1
x[Tmp.new] = 2
puts "#{Tmp.new.hash == Tmp.new.hash}"
puts "#{Tmp.new.eql? Tmp.new}"
puts "#{x}"
end
给予:
==========================
true
false
{#<Tmp:0x0000407e40e408>=>1, #<Tmp:0x0000407e40e3b8>=>2}
这似乎与文档相矛盾。这是使用ruby v2.2.4的神器吗? (我使用的是 Sketchup 2017 自带的 ruby)
【问题讨论】:
-
注意:有一个随机的
hash值会导致问题。每次在存储相同数据的同一个对象上调用它时都需要返回相同的值。 -
@tadman 我使用
rand仅用于示例目的。我通常不会这样做。 -
是的,只是想弄清楚这里的意图。
-
读了几遍后,我仍然不确定问题是什么。最后一个示例按预期工作,您已强制它们不是
eql?,因此您获得了两个单独的键。 -
@tadman,是的,但我希望最后一个示例也应该与最后一个示例具有相同的结果,因为
#hash没有给出恒定值,即使#eql?给出true.
标签: ruby