EQL?重新定义Object #hash后的行为

时间:2014-05-28 12:23:18

标签: ruby

Ruby API说:

  

eql?如果obj和其他引用相同的哈希键,则返回true。

我更改了Object的哈希方法:

class Object
 def hash
   1
 end
end

Object.new.hash == Object.new.hash
# => true

Object.new.eql? Object.new
# => false

我不明白为什么第二个语句会返回false;根据上面的Ruby Object API,它应该返回true

3 个答案:

答案 0 :(得分:2)

这不是文档所说的,而且#34;相同的哈希键"与您发布的代码无关。

hash使用暗示创建一个哈希键,a.eql?(b) 表示 a.hash == b.hash。这与打破hash并期望未经修改的eql?以您期望的方式工作的方式不同。

必须重写

eql?以提供您想要的语义,例如,自定义类可以覆盖eql?以提供特定于域的等效性。如果您希望其他代码正常工作,仍然需要遵循上述hash合同含义。

(这类似于Java口号"如果覆盖hashCode,则覆盖equals,例如http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20。)

答案 1 :(得分:1)

你正在创建两个新对象,它们将永远不会相同。

a = Object.new
=> #<Object:0x007fd16b35c8b8>
b = Object.new
=> #<Object:0x007fd16b355540>

我会将你推荐回this SO question

答案 2 :(得分:1)

这是一个documentation错误。你读得正确,但文件是矛盾的。

  • 一方面,文档说:

      

    eql?如果obj和其他引用相同的哈希键,则返回true。

    你可以像在你的问题中所期望的那样:

    Object.new.eql? Object.new
    # => true
    
  • 另一方面,它也说:

      

    对于Object类的对象,eql?是==。

    的同义词

    其中==的定义为:

      

    在Object级别,只有当obj和other是同一个对象时,==才返回true。

    逻辑上遵循:

      

    对于Object类的对象,eql?仅当obj和other是同一个对象时才返回true。

    你应该期待:

    Object.new.eql? Object.new
    # => false
    

因此,文件提出了相互矛盾的主张。你依靠其中一个,并期待,但看看实际结果,现实似乎支持第二个主张。