根据此post,可以在splat参数之后有一个可选的关键字参数。如果splat参数引入了一个数组数组,则该方法有效,但是当它是一个哈希数组时,则无效
例如,如果被调用的方法定义为
def call(*scores, alpha: nil)
puts scores
end
然后这有效
scores = [[1,2],[3,4]]
call(*scores)
但这不是
scores = [ {a: 1}, {b: 3}]
call(*scores)
给出以下内容(使用ruby 2.4.4)
ArgumentError: unknown keyword: b
但这可行
scores = [ {a: 1}, {b: 3}]
call(*scores, alpha: nil)
这是怎么回事?
答案 0 :(得分:3)
splat运算符将数组拆分为参数。
但是,如果将其包装在数组中,它将再次起作用,但是现在它是数组中的一个数组,并且仍然被视为传递给您的方法的单个参数。
call([*scores]) #no error
还要说明一下为什么会出现错误,请看这里发生的情况:
def call(*scores, alpha: nil)
puts scores.inspect
end
call(*scores[0]) #=> #[[:a, 1]]
更新:感谢@Stefan,导致错误的原因实际上是您的方法接受关键字参数,这显然是一个已知的错误。参见Keyword arguments unpacking (splat) in Ruby
最后一个示例起作用的原因是,通过将第二个参数传递给方法,splat会将第一个参数作为数组处理,而不是尝试将其拆分为2个参数。
更多信息,请参见Ruby, Source Code of Splat?
另请参见https://www.rubyguides.com/2018/07/ruby-operators/#Ruby_Splat_Operator
答案 1 :(得分:2)
*
将数组元素转换为参数列表,因此:
call(*[{a: 1}, {b: 3}])
等效于:
call({a: 1}, {b: 3})
Ruby还将隐式地将散列转换为关键字参数(没有**
),因此上面的代码等效于:†
call({a: 1}, b: 3)
因此,{a: 1}
被视为位置参数,而b: 3
(或{b: 3}
)被视为关键字参数。而且由于call
不使用名为b
的关键字参数,所以您得到ArgumentError: unknown keyword: b
。
为避免这种情况,您可以传递一个额外的空哈希‡作为最后一个参数:
call({a:1}, {b:2}, {})
或:
call(*[{a:1}, {b:2}], {})
或
scores = [{a:1}, {b:2}]
call(*scores, {})
†有一个feature request在Ruby 3中添加“真实”关键字参数。
‡ IMO,使用call(*scores, **{})
表示“无关键字参数”会更正确,但是由于bug,目前无法使用。但是,您可以使用call(*scores, **Hash.new)