【问题标题】:Why is ruby .hash producing different output every time为什么 ruby​​ .hash 每次都会产生不同的输出
【发布时间】:2019-08-23 10:06:12
【问题描述】:

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

puts "This is a string".hash

这里发生了什么?对于任何给定的输入字符串,我应该如何更改它以从 .hash 中获得一致的、可重现的值?

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

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

【问题讨论】:

  • 根据文档:“对象的哈希值在 Ruby 的调用或实现中可能不相同。如果您需要跨 Ruby 调用和实现的稳定标识符,则需要使用自定义生成一个方法。” ruby-doc.org/core-2.4.1/Object.html#method-i-hash你能提供更多关于什么得到一致结果的信息吗?
  • 您显然使用的是 Ruby 2.3 之前的版本。该版本改变了文字的存储方式。具体来说,literals having the same value point to the same object,所以对于 v2.3+​​,"This is a string".hash == "This is a string".hash #=> true。我希望对于早期版本"This is a string".freeze.hash == "This is a string".hash #=> true。你能测试一下吗?
  • @CarySwoveland:仍然不能保证这个值在调用中是相同的。
  • @Jörg,是的,但我们不知道 OP 是在询问调用之间的一致性还是单个调用的一致性。

标签: ruby hash


【解决方案1】:

这是怎么回事?

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

The documentation 在这里非常明确(粗体强调我的):

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

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

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

不使用它。

【讨论】:

    【解决方案2】:

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

    • 尽量减少冲突 - 有时可能会发生冲突,因为如果有多个项目,Hash 中的存储桶可能会退回到搜索中
    • 虚拟机的整个生命周期内保持稳定 - 不需要,因为每次都会重新“重建”哈希,即使在您进行封送处理时也是如此

    它应该满足以下约束

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

    可以通过多种方式满足第二个要求。例如,它可以通过使用更快的散列函数来满足。但它也可以通过查找“任意”计算的哈希值来满足,例如,字符串,如果这个特定的字符串是另一个字符串的副本 - 通过重用该值。另一种方法 - 有时也被应用 - 是从 Ruby 对象 ID 派生散列值 - 每个定义都会在虚拟机的运行过程中发生变化。

    确实,Jörg 所说的 - 出于您的目的,hash() 函数并不适合,因为它是为不同的用例而设计的。虽然有很多替代方案 - 通常的 SHA、杂音散列、xxhash 等 - 可能满足您的要求并保证是内容派生的。

    【讨论】:

      猜你喜欢
      • 2016-03-29
      • 2012-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-26
      • 1970-01-01
      • 1970-01-01
      • 2017-05-02
      相关资源
      最近更新 更多