我可以在 Ruby 3.1 中解构块参数中的哈希值,例如 `|foo:|` 吗?

Hen*_*k N 6 ruby

在 Ruby 2.7 中,我可以有效地解构块参数中的哈希:

>> RUBY_VERSION
=> "2.7.6"
>> [{foo: 123}].each { |foo:| p foo }
123
=> [{:foo=>123}]
Run Code Online (Sandbox Code Playgroud)

在 Ruby 3.1 中,我不能:

>> RUBY_VERSION
=> "3.1.2"
>> [{foo: 123}].each { |foo:| p foo }
(irb):7:in `block in <top (required)>': missing keyword: :foo (ArgumentError)
Run Code Online (Sandbox Code Playgroud)

可以在参数列表之外对其进行模式匹配:

[{foo: 123}].each { |x| x => {foo:}; p foo }
Run Code Online (Sandbox Code Playgroud)

但如果可能的话,我正在寻找参数列表中的某些内容。

Ste*_*fan 6

简短回答:不

each只是将{foo: 123}哈希值作为块参数传递,但 Ruby 3 期望foo:传递实际的关键字。它相当于:

def m(foo:)
  p foo
end

m({foo: 123})
# ArgumentError: wrong number of arguments (given 1, expected 0; required keyword: foo)
Run Code Online (Sandbox Code Playgroud)

您必须传递关键字参数或通过以下方式转换哈希**

m(foo: 123)
# 123

m(**{foo: 123})
# 123
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,这都必须在调用方一侧“修复”。

在您的代码中,调用者是each. 为了让您的代码正常工作,您可以定义自己的each变体来执行所需的转换:

module Enumerable
  def each_keyword
    each { |hash| yield **hash }
  end
end
Run Code Online (Sandbox Code Playgroud)

对于示例数据,其效果符合预期:

[{foo: 123}].each_keyword { |foo:| p foo }
# 123
Run Code Online (Sandbox Code Playgroud)

但是,我只是坚持each并从传递的哈希中获取值:

[{foo: 123}].each { |h| p h[:foo] }
# 123
Run Code Online (Sandbox Code Playgroud)

如果你有一个散列,你可能应该将它视为一个。