【发布时间】: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)。这就是它们被修改的原因。当您有两个哈希
h和i并执行{**h, **i, d: 5}时,只有h被修改,而不是i。 -
还有一件事 - 如果你直接在 Rubyforum 上发帖,它不会在邮件列表中可用,而反向是可以的。所以最好把它贴在邮件列表中。我说的是当前的网关问题。
-
@sawa 表达式的结果与
h是同一个对象,这是一个有趣的见解,但还有更多。考虑h = { a: 1 }; { **h, a: 99, **h }。由于最终结果是{ a: 99 },我们可以看到,即使我们到达最终的**h,h[:a]已经被覆盖了。
标签: ruby hash syntax splat double-splat