关键字参数在Ruby

时间:2017-03-17 03:27:24

标签: ruby hash keyword-argument ruby-2.2 double-splat

下面发生的事情对我来说似乎有点奇怪。

def f(a, b)
  puts "#{a} :: #{b}"
end

f(*[1, 2], **{}) # prints "1 :: 2"

hash = {}
f(*[1, 2], **hash)
ArgumentError: wrong number of arguments (3 for 2)

f(*[1, 2], **Hash.new)
ArgumentError: wrong number of arguments (3 for 2)

这是编译器优化功能吗?

3 个答案:

答案 0 :(得分:7)

这是Ruby的错误已多次报告(例如我here)但尚未修复。

我想,由于引入了关键字参数功能,双splat语法变得模糊不清,这就是这个bug的间接原因。我听说Matz正在考虑在未来的Ruby版本中引入一种新的语法来区分哈希和关键字参数。

答案 1 :(得分:2)

[编辑:完成我的后,我看到@ sawa的回答。我是对的:这是一个错误!]

当文字空哈希被双重绘制并且空哈希值是变量值被双击时,获得了不同的结果,在我看来, prima facia 证明它& #39;由于Ruby中的错误。要了解错误可能存在的原因,请首先考虑将双splatted哈希传递给方法的原因。

假设我们使用一些关键字参数定义一个方法:

def my_method(x, a: 'cat', b: 'dog')
  [x, a, b]
end

my_method(1)
  #=> [1, "cat", "dog"] 

默认值适用于两个关键字参数。现在试试:

my_method(1, a: 2)
  #=> [1, 2, "dog"]

现在让我们使用双splatted哈希。

h = { a: 2, b: 3 }

my_method(1, **h)
 #=> [1, 2, 3] 

这与所需的关键字参数(Ruby 2.1 +)相同。

def my_method(x, a:, b:)
  [x, a, b]
end

my_method(1, **h)
  #=> [1, 2, 3]

但是,要使用双splatted散列作为参数,散列不能包含未在方法定义中作为参数列出的键。

def my_method(x, a:)
  [x, a]
end

h = { a: 2, b: 3 }

my_method(1, **h)
  #=> ArgumentError: unknown keyword: b

因此出现了这样的问题:考虑到所有哈希的键(无)都作为参数包含在方法定义中,可以将双splatted空哈希作为参数传递(这种情况下它不会产生任何影响)?我们来试试吧。

def my_method(x)
  [x]
end

my_method(1, **{})
  #=> [1]

是!

h = {}
my_method(1, **h)
  #=> ArgumentError: wrong number of arguments (given 2, expected 1)

没有!

这没有任何意义。所以假设这是一个错误,它怎么可能出现?我怀疑它可能与Ruby的优化有关,正如OP所建议的那样。空哈希是一个文字,可以在Ruby的代码中早先处理它,而不是变量的值。我猜是谁写了早期的代码回答了"是"对于我上面提出的问题,无论是谁写了后面的代码都回答了#34; no",或者没有考虑到那时空哈希的情况。

如果这个错误理论没有被击落,那么OP或其他人应该报告它。

答案 2 :(得分:1)

我感觉你正在绊倒splat运算符与空哈希结构相关的特性。看起来splatting一个空的内联哈希导致它消失,但其他任何东西都被扩展为某种类型的参数。

这实际上可能是Ruby中的一个错误,虽然它是如此奇怪的边缘情况我并不感到惊讶。

您的f函数不接受任何类型的关键字参数,因此如果有足够的力量尝试提供它们,它将会失败。最后两个例子似乎试图强制将空哈希作为文字参数。