如果我多次运行以下单行 ruby 脚本,它每次都会产生不同的输出值。
puts "This is a string".hash
这是怎么回事?我应该如何更改它以从任何给定输入字符串的 .hash 中获取一致的、可重现的值?
编辑:"可能的重复"建议其他哈希方法。我正在尝试重现另一个我无法控制的脚本的行为,该脚本使用 .hash 并获得一致的结果。更改哈希方法不是一种选择。
编辑#2:如下面的另一条评论所述,我要重现其行为的另一个脚本位于.exe包装器中。它的历史可以追溯到 2006 年,这意味着 Ruby 版本必须是 1.8.5 或更早版本。#hash 方法在早期版本的 Ruby 中的工作方式是否不同,如果是这样,是否有人生成了复制这些早期版本行为的脚本?(它可以是不同的名称。
怎么回事?
在程序的生存期内,不同对象的#hash
应该不同,而相同对象的应该相同。绝对不能保证程序的不同调用的值是什么。
这里的文档非常明确(粗体强调我的(:
对象的哈希值在 Ruby 的调用或实现中可能不相同。如果您需要跨 Ruby 调用和实现的稳定标识符,则需要使用自定义方法生成一个。
[注意:由于某种原因,当前版本的 Ruby 的文档无法在 ruby-doc.org 上正确呈现。不过,它在当前的主分支中是相同的。
我应该如何更改它以从任何给定输入字符串的 .hash 中获取一致的、可重现的值?
不使用它。
>我认为了解#hash
的用途可能会有所帮助。它用于将 Ruby 对象存储到Hash
数据结构的特定存储桶中 - 或者,将其包含在Set
中 - 但这是一个实现细节,因为 Ruby 集是在哈希的"之上"实现的。它不用于消化值。一旦你知道这一点,很明显#hash
不应该满足以下约束:
- 尽量减少冲突 -有时发生冲突是可以的,因为如果有多个项目,哈希中的存储桶可能会回归到搜索中
- 在虚拟机的整个生命周期内保持稳定 - 不是必需的,因为每次都会重新"重建"哈希,即使您进行封送处理也是如此
它应满足以下约束
- 在虚拟机的相同生存期内稳定 - 否则项目可能必须"迁移"到 Hash 中的其他存储桶,这是不可能实现的。这就是为什么字符串在用作哈希键时会被冻结的原因
- 快速计算
- 适合Ruby Hash桶使用的任意"密钥大小"(在MRI中,我相信它是
st_index_t
的大小(
第二个要求可以通过多种方式满足。例如,可以通过使用更快的哈希函数来满足它。但它也可以通过查找"任意"计算的哈希值来满足,例如字符串,如果这个特定的字符串是另一个字符串的副本 - 通过重用该值。另一种方法(有时也应用(是从 Ruby 对象 ID 派生哈希值 - 根据定义,哈希值在虚拟机运行中会发生变化。
Jörg 确实如此 - 就您的目的而言,hash(( 函数不太合适,因为它是为不同的用例制作的。不过,还有大量的替代方案 - 通常的SHA,杂音哈希,xxhash等 - 可以满足您的要求并保证是内容派生的。