为什么ruby .hash每次都会产生不同的输出

时间:2019-08-22 14:18:52

标签: ruby hash

如果我多次运行以下单行ruby脚本,则每次都会产生不同的输出值。

puts "This is a string".hash

这是怎么回事?对于任何给定的输入字符串,我应该如何更改它以使其从.hash获得一致,可重现的值?

编辑:“可能重复”建议其他哈希方法。我正在尝试重现另一个我无法控制使用.hash并获得一致结果的脚本的行为。不能更改哈希方法。

编辑#2:如下面的另一条注释所述,我要重现其行为的另一个脚本位于.exe包装器内。它可以追溯到2006年,这意味着Ruby版本必须为1.8.5或更早版本。 #hash方法在Ruby早期版本中的工作方式是否有所不同,如果是,是否有人生产了可复制那些早期版本行为的脚本? (可以使用其他名称。)

2 个答案:

答案 0 :(得分:3)

  

这是怎么回事?

#hash对于不同的对象应该是不同的,对于相等的对象,在程序的生存期内应该相同。绝对不能保证程序不同调用之间的值是什么。

The documentation在这里非常明确(粗体是我的重点):

  

对象的哈希值在调用之间或Ruby的实现中可能不相同。如果您需要跨Ruby调用和实现的稳定标识符,则需要使用自定义方法生成一个标识符

[注意:由于某些原因,Ruby的当前版本的文档未在ruby-doc.org上正确呈现。 It is identical in the current master branch, though.]

  

对于任何给定的输入字符串,我应该如何更改它以使其从.hash获得一致,可重现的值?

不使用它。

答案 1 :(得分:0)

我认为了解#hash的含义可能会有所帮助。它用于将Ruby对象存储到Hash数据结构的特定存储区中-或,或者将其包含在Set中-但这是一个实现细节,因为Ruby Set是在Hash的“顶部”实现的。它不用于摘要值。一旦知道,#hash显然不应该满足以下约束:

  • 最大限度地减少冲突-有时发生冲突 很好,因为如果有多个项目,则哈希中的存储桶可以退回到搜索中
  • 虚拟机的整个生命周期中保持稳定-不需要,因为即使您进行封送处理,哈希也每次都会“重新构建”

它应满足以下约束条件

  • 在VM的相同生命周期内保持稳定-否则可能需要将该项目“迁移”到Hash中的其他存储桶中,这是不可能实现的。这就是为什么字符串在用作哈希键时会冻结
  • 快速计算
  • 适合Ruby Hash存储桶使用的任意“密钥大小”(在MRI中,我相信是st_index_t的大小)

可以通过多种方式满足第二个要求。例如,可以通过使用更快的哈希函数来满足要求。但是,也可以通过查找“任意”计算得出的哈希值来满足此要求,例如查找字符串,以及如果此特定字符串是另一个字符串的重复-通过重用该值。另一种方法(有时也应用)是从Ruby对象ID导出哈希值,该哈希值根据定义在虚拟机的运行中发生变化。

所以Jörg所说的确实如此-出于您的目的,hash()函数不是一个很好的选择,因为它是为不同的用例而设计的。但是,还有很多替代方法-常用的SHA,杂项哈希,xxhash等-可能会满足您的要求并保证是基于内容的。