字符串值作为哈希键,创建副本

时间:2014-05-08 12:53:36

标签: ruby string hash

使用字符串对irb进行试验并注意到当引用字符串的变量用作Hash中的键值时,会创建String的新副本而不是对原始对象的引用,但情况并非如此使用数组:

1.9.3-p448 :051 > a = 'str1' 
 => "str1"
1.9.3-p448 :052 > b = 'str2' 
 => "str2" 
1.9.3-p448 :053 > arr = [a,b] 
 => ["str1", "str2"] 
1.9.3-p448 :054 > arr[0].object_id == a.object_id 
 => true 
1.9.3-p448 :055 > hash = { a => b } 
 => {"str1"=>"str2"} 
1.9.3-p448 :056 > hash.keys[0].object_id == a.object_id 
 => false

我理解如果我只是坚持使用符号,我就不会问这个问题。

制作字符串副本的目的是什么?我知道字符串比较仍然可以工作,但是object_id比较肯定会更快吗?

2 个答案:

答案 0 :(得分:3)

来自Hash.[]=文档:

  

键在作为键使用时不应更改其值(a   解冻后传递的字符串将被复制并冻结。

因为默认情况下,字符串在ruby中不是不可变的,理论上你可以在将它们设置为哈希中的键后更改它们。如果你这样做 - 你的哈希将变得无效,因为它将无法正确找到这些密钥。

由于字符串无处不在并且经常被引用使用,因此Ruby可以保护其哈希值免受意外错误的影响,而这些错误很难检测到。

答案 1 :(得分:1)

大多数常见的密钥都是不可变的:数字,符号,日期。然而,字符串是可变的,正如Uri Agassi所写,Ruby保护哈希不受错误的影响。对于用作键的数组,它可能不会这样做,可能是出于性能原因(可能是大型数组),或者数组通常不用作键。哈希值通常通过每个对象具有的hash方法的结果进行比较。如果您希望通过object_id进行比较,则可以将其打开:hash.compare_by_identity