双splat运算符破坏性地修改哈希 – 这是一个Ruby错误吗?

我注意到我发现Ruby 2.1.1中的** (双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] 

arrays始终保持不变。


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

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


我也在Ruby论坛中问过这个问题。

UPDATE

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

这个问题的答案似乎是:

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

  2. **运算符的行为在核心库rdoc中非常简要地记录 。

感谢几位评论者的建议,我已将错误发布到Ruby trunk问题跟踪器 。


更新:

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

我注意到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中,以double splat提供的哈希覆盖列表中第一项的相同键。