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

时间:2014-04-25 00:49:33

标签: ruby hash syntax splat double-splat

我注意到我发现在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 +中修复。

2 个答案:

答案 0 :(得分:7)

问题的答案似乎是:

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

  2. core library rdoc中非常简要地记录了**运算符的行为。

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


    <强>更新

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

答案 1 :(得分:1)

我注意到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中,值为&#39; b&#39;

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

我不确定它应该是什么?

在2.3.1中,以double splat提供的哈希覆盖列表中第一项的相同键。