哈希的compare_by_identity如何运作?

Aru*_*hit 1 ruby hash

我首先运行下面的代码第一部分并获得所需的输出,现在只是为了解决它并做一些研究我做了第二部分.

第一部分

irb(main):001:0> h1 = { "a" => 100, "b" => 200, :c => "c" }
=> {"a"=>100, "b"=>200, :c=>"c"}
irb(main):002:0> h1["a"]
=> 100
irb(main):002:0> h1[:c]
=> "c"
Run Code Online (Sandbox Code Playgroud)

第二部分

irb(main):003:0> h1.compare_by_identity
=> {"a"=>100, "b"=>200, :c=>"c"}
irb(main):004:0> h1.compare_by_identity?
=> true
irb(main):005:0> h1["a"]
=> nil
irb(main):006:0> h1[:c]
=> "c"
irb(main):007:0>
Run Code Online (Sandbox Code Playgroud)

如何h1["a"]在第一部分和第二部分给出不同的值,但不一样h1[:c]

我正在使用Ruby 1.9.3.

And*_*all 12

对文档compare_by_identity这样说:

使得hsh通过他们的身份比较它的钥匙,也就是说,它会考虑完全一样的对象作为相同的密钥.

通常,哈希键将使用匹配eql?,但compare_by_identity将使用它们匹配equal?(这大致相当于比较object_ids*).由于具有相同值的字符串的不同实例具有不同的object_ids,因此它不匹配.但是,符号始终具有相同的符号object_id,因此它会继续匹配.

hash = { 'a' => 'str a', 'b' => 'str b', :c => 'sym c' }
hash.compare_by_identity

hash.keys.map(&:object_id)      #=> [70179407935200, 70179407935180, 358408]
['a', 'b', :c].map(&:object_id) #=> [70179405705480, 70179405705460, 358408]

hash.keys.zip(['a', 'b', :c]).map { |pair| pair.inject(:eql?) }   #=> [true, true, true]
hash.keys.zip(['a', 'b', :c]).map { |pair| pair.inject(:equal?) } #=> [false, false, true]

a_key = hash.keys.first  #=> 'a'
hash['a']   #=> nil
hash[a_key] #=> 'str a'
hash[:c]    #=> 'sym c'
Run Code Online (Sandbox Code Playgroud)

如您所见,object_id字符串的object_ids与散列中的键的s 不匹配,但符号的s 不匹配.实际上,如果重复运行'a'.object_id&'b'.object_id(或调用object_id任何字符串),每次都会得到不同的值.

*这里需要注意的是,人们可以覆盖object_id,但它对比较没有影响,因为equal?实际上并没有使用object_id.此外,重新定义equal?将改变这一点,但不建议在Ruby文档中明确这样做.

  • 这是错的.`Hash`从不使用`==`来表示平等.它使用`eql?`或`equal?`,具体取决于`compare_by_identity`的设置. (2认同)
  • @JörgWMittag你是对的,我已经更新了我的答案以反映这一点 - 谢谢!我认为我的错误主要在于查看`Object#eql?`的文档太快了,它显示它与`equal?`和`==`相同,并且错误地忽略了它们通常被单独覆盖. (2认同)