【问题标题】:Double-splat operator destructively modifies hash – is this a Ruby bug?Double-splat 运算符破坏性地修改了哈希——这是一个 Ruby 错误吗?
【发布时间】:2014-07-14 14:24:08
【问题描述】:

我注意到我发现 Ruby 2.1.1 中的 ** (double-splat) 运算符有一个非常令人惊讶的行为。

当在**hash 之前使用键值对时,哈希值保持不变;但是,当键值对仅在**hash 之后使用时,哈希值会被永久修改。

h = { b: 2 }

{ a: 1, **h }        # => { a: 1, b: 2 }
h                    # => { b: 2 }

{ a: 1, **h, c: 3 }  # => { a: 1, b: 2, c: 3 }
h                    # => { b: 2 }

{ **h, c: 3 }        # => { b: 2, c: 3 }
h                    # => { b: 2, c: 3 }

为了比较,请考虑数组上的单* 运算符的行为:

a = [2]

[1, *a]     # => [1, 2]
a           # => [2]

[1, *a, 3]  # => [1, 2, 3]
a           # => [2]

[*a, 3]     # => [2, 3]
a           # => [2]

数组始终保持不变。


我们认为** 有时具有破坏性的行为是故意的,还是看起来更像是一个错误?

无论哪种情况,描述** 运算符如何工作的文档在哪里?


我也问过这个问题in the Ruby Forum

更新

该错误已在 Ruby 2.1.3+ 中修复。

【问题讨论】:

  • 参数列表中的使用在核心文档ruby-doc.org/core-2.1.1/doc/syntax/methods_rdoc.html中。散列和数组文字插值似乎没有出现在任何地方,尽管单次口角至少有一个规范:github.com/rubyspec/rubyspec/blob/master/language/splat_spec.rb。双拍没有类似的东西。 Ruby 语义似乎确实是民间传说。我确信这是一个错误,因为未记录的语言功能可能是错误的!
  • 我什至不知道您可以在无方法签名中使用它...
  • 如果组合散列是散列,则看起来组合散列与其中的第一个元素是同一个对象(它们具有相同的对象 id)。这就是它们被修改的原因。当您有两个哈希 hi 并执行 {**h, **i, d: 5} 时,只有 h 被修改,而不是 i
  • 还有一件事 - 如果你直接在 Rubyforum 上发帖,它不会在邮件列表中可用,而反向是可以的。所以最好把它贴在邮件列表中。我说的是当前的网关问题。
  • @sawa 表达式的结果与h 是同一个对象,这是一个有趣的见解,但还有更多。考虑h = { a: 1 }; { **h, a: 99, **h }。由于最终结果是{ a: 99 },我们可以看到,即使我们到达最终的**hh[:a] 已经被覆盖了。

标签: ruby hash syntax splat double-splat


【解决方案1】:

问题的答案似乎是:

  1. 这可能是一个错误,而不是故意的。

  2. ** 运算符的行为在 core library rdoc 中有非常简短的记录。

感谢几位评论者的建议,我已将该错误发布到Ruby trunk issue tracker


更新:

该错误已在changeset r45724 中修复。那里的评论是“keyword splat 应该是非破坏性的”,这使得这是一个权威的答案。

【讨论】:

  • 该错误似乎已经是fixed。很快。
  • @sawa 它很快,但需要说它看起来像一个黑客然后是修复。只是用哈希的浅拷贝覆盖先前调用的指针,省略完整条件。感觉有点尴尬。
【解决方案2】:

我注意到 2.1.5 和 2.3.1 之间的差异

例子是一个irb方法和调用它的方式

$ irb
>> def foo(opts) opts end
=> :foo
>> foo a: 'a', ** {a: 'b'}

在 2.1.5 中,以下导致保留值

=> {:a=>"a"}

在 2.3.1 中,值为 'b'

(irb):2: warning: duplicated key at line 2 ignored: :a
=> {:a=>"b"}

我不确定应该是哪个?

在 2.3.1 中,作为双 splat 提供的哈希会覆盖列表中第一项的相同键。

【讨论】:

    猜你喜欢
    • 2021-01-31
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 2013-07-04
    • 2021-10-04
    • 1970-01-01
    相关资源
    最近更新 更多