Double-splat operator destructively modifies hash

2019-01-15 07:43发布

I noticed what I find to be a very surprising behavior with the ** (double-splat) operator in Ruby 2.1.1.

When key-value pairs are used before a **hash, the hash remains unmodified; however, when key-value pairs are only used after the **hash, the hash is permanently modified.

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 }

For comparison, consider the behavior of the single-* operator on arrays:

a = [2]

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

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

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

The array remains unchanged throughout.


Do we suppose the sometimes-destructive behavior of ** is intentional, or does it look more like a bug?

In either case, where is the documentation describing how the ** operator is meant to work?


I also asked this question in the Ruby Forum.

UPDATE

The bug is fixed in Ruby 2.1.3+.

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-01-15 08:25

The answers to the question seem to be:

  1. It's probably a bug, rather than intentional.

  2. The behavior of the ** operator is documented very briefly in the core library rdoc.

Thanks to the suggestions of several commenters, I've posted the bug to the Ruby trunk issue tracker.


UPDATE:

The bug was fixed in changeset r45724. The comment there was "keyword splat should be non-destructive," which makes this an authoritative answer.

查看更多
\"骚年 ilove
3楼-- · 2019-01-15 08:28

I noticed the diff between 2.1.5 and 2.3.1

Example is an irb method and a way of calling it

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

In 2.1.5 the following results in retaining value

=> {:a=>"a"}

In 2.3.1 the value is 'b'

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

I am not sure which it should be?

In 2.3.1 the hash provided as double splat overrides the same key of the first item in a list.

查看更多
登录 后发表回答