Ruby 中的关键字参数解包 (splat)
Keyword arguments unpacking (splat) in Ruby
我觉得下面发生的事情有点奇怪。
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)
这是编译器优化功能吗?
我觉得您被 splat 运算符与空哈希结构相关的特性绊倒了。看起来一个空的内联散列会导致它消失,但其他任何东西都会作为某种参数展开。
这实际上可能是 Ruby 中的一个错误,尽管这是一个非常古怪的边缘情况,但我并不感到惊讶。
您的 f
函数不接受任何类型的关键字参数,因此如果进行了足够有力的尝试来提供它们,它将失败。最后两个示例似乎试图将空散列作为文字参数。
这是一个 Ruby 的错误,已多次报告(例如我 here)但尚未修复。
我猜想自从引入了关键字参数特性后,double splat 语法就变得模糊了,这也是导致这个bug的间接原因。我听说 Matz 正在考虑在 Ruby 的某个未来版本中引入一种新语法来区分散列和关键字参数。
[编辑:完成我的回答后我看到了@sawa 的回答。我是对的:这是一个错误!]
当字面的空散列被双拼和作为变量值的空散列被双拼时,会得到不同的结果,在我看来 prima facia 证明这是由于 Ruby 中的错误所致。要了解为什么可能存在错误,请首先考虑将双散列哈希传递给方法的原因。
假设我们用一些关键字参数定义了一个方法:
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"]
现在让我们使用双拼散列。
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]
但是,要使用双拼散列作为参数,散列不能包含未在方法定义中列为参数的键。
def my_method(x, a:)
[x, a]
end
h = { a: 2, b: 3 }
my_method(1, **h)
#=> ArgumentError: unknown keyword: b
因此出现了一个问题:考虑到所有散列的键 (none) 都作为参数包含在方法定义中(在这种情况下它会没有效果)?我们来试试吧。
def my_method(x)
[x]
end
my_method(1, **{})
#=> [1]
是的!
h = {}
my_method(1, **h)
#=> ArgumentError: wrong number of arguments (given 2, expected 1)
没有!
这毫无意义。所以假设这是一个错误,它是如何出现的?我怀疑这可能与 OP 所建议的 Ruby 的优化有关。如果空散列是一个文字,那么可以在 Ruby 的代码中比它是变量的值更早地处理它。我猜想写前面代码的人对我上面提出的问题回答了"yes",而写后面代码的人回答了"no",或者当时没有考虑空散列的情况。
如果这个错误理论没有被击落,OP 或其他人应该报告它。
我觉得下面发生的事情有点奇怪。
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)
这是编译器优化功能吗?
我觉得您被 splat 运算符与空哈希结构相关的特性绊倒了。看起来一个空的内联散列会导致它消失,但其他任何东西都会作为某种参数展开。
这实际上可能是 Ruby 中的一个错误,尽管这是一个非常古怪的边缘情况,但我并不感到惊讶。
您的 f
函数不接受任何类型的关键字参数,因此如果进行了足够有力的尝试来提供它们,它将失败。最后两个示例似乎试图将空散列作为文字参数。
这是一个 Ruby 的错误,已多次报告(例如我 here)但尚未修复。
我猜想自从引入了关键字参数特性后,double splat 语法就变得模糊了,这也是导致这个bug的间接原因。我听说 Matz 正在考虑在 Ruby 的某个未来版本中引入一种新语法来区分散列和关键字参数。
[编辑:完成我的回答后我看到了@sawa 的回答。我是对的:这是一个错误!]
当字面的空散列被双拼和作为变量值的空散列被双拼时,会得到不同的结果,在我看来 prima facia 证明这是由于 Ruby 中的错误所致。要了解为什么可能存在错误,请首先考虑将双散列哈希传递给方法的原因。
假设我们用一些关键字参数定义了一个方法:
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"]
现在让我们使用双拼散列。
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]
但是,要使用双拼散列作为参数,散列不能包含未在方法定义中列为参数的键。
def my_method(x, a:)
[x, a]
end
h = { a: 2, b: 3 }
my_method(1, **h)
#=> ArgumentError: unknown keyword: b
因此出现了一个问题:考虑到所有散列的键 (none) 都作为参数包含在方法定义中(在这种情况下它会没有效果)?我们来试试吧。
def my_method(x)
[x]
end
my_method(1, **{})
#=> [1]
是的!
h = {}
my_method(1, **h)
#=> ArgumentError: wrong number of arguments (given 2, expected 1)
没有!
这毫无意义。所以假设这是一个错误,它是如何出现的?我怀疑这可能与 OP 所建议的 Ruby 的优化有关。如果空散列是一个文字,那么可以在 Ruby 的代码中比它是变量的值更早地处理它。我猜想写前面代码的人对我上面提出的问题回答了"yes",而写后面代码的人回答了"no",或者当时没有考虑空散列的情况。
如果这个错误理论没有被击落,OP 或其他人应该报告它。