在方法调用中使用Ruby的双splat(`**`)有什么意义?

Ren*_*non 6 ruby syntax double-splat

使用单个splat,我们可以将数组扩展为多个参数,这与直接传递数组非常不同:

def foo(a, b = nil, c = nil)
  a
end

args = [1, 2, 3]

foo(args)  # Evaluates to foo([1, 2, 3]) => [1, 2, 3]
foo(*args) # Evaluates to foo(1, 2, 3)   => 1
Run Code Online (Sandbox Code Playgroud)

但是,使用关键字参数,我看不出任何差异,因为它们只是哈希的语法糖:

def foo(key:)
  key
end

args = { key: 'value' }

foo(args)   # Evaluates to foo(key: 'value') => 'value'
foo(**args) # Evaluates to foo(key: 'value') => 'value'
Run Code Online (Sandbox Code Playgroud)

除了良好的对称性,是否有任何实际的理由在方法调用上使用双splats?(请注意,这与在方法定义中使用它们不同)

use*_*951 5

使用单个参数的示例是退化情况.

看一个非常重要的案例,您可以快速看到拥有新**运算符的优势:

def foo (args)
  return args
end

h1 = { b: 2 }
h2 = { c: 3 }

foo(a: 1, **h1)       # => {:a=>1, :b=>2}
foo(a: 1, **h1, **h2) # => {:a=>1, :b=>2, :c=>3}
foo(a: 1, h1)         # Syntax Error: syntax error, unexpected ')', expecting =>
foo(h1, h2)           # ArgumentError: wrong number of arguments (2 for 1)
Run Code Online (Sandbox Code Playgroud)

使用**运算符允许我们在命令行中将现有哈希值与文字键值参数合并在一起.(*当然,使用参数数组也是如此.)

遗憾的是,您必须小心这种行为,具体取决于您使用的Ruby版本.至少在Ruby 2.1.1中,有一个错误,即splatted hash 会被破坏性修改,尽管它已被修补.