处理带有可选参数后跟关键字参数列表的方法

Handling a method with an optional argument followed by a list of keyword arguments

我想将一个可选参数(任何数据类型,甚至是哈希)后跟关键字参数列表(可以为空)传递给方法。

这是我得到的:

def my_method(subject = nil, **options)
  [subject, options]
end

在以下情况下,方法输出符合预期:

当传递 Hash 作为主题且没有选项时,期望的结果是:

my_method({foo: 'foo'})
# => [{:foo=>"foo"}, {}]

但我得到以下信息;我没有得到正确的主题:

my_method({foo: 'foo'})
# => [nil, {:foo=>"foo"}]

my_method(foo: 'foo')是否等同于my_method({foo: 'foo'})?关于如何获得预期结果的任何想法?

据我所知,这是 Ruby 传递参数的限制。它无法区分 my_method({foo: 'foo'})my_method(foo: 'foo')

为什么不用这个来破解呢?

if subject.is_a?(Hash) && options.empty?
  subject, options = nil, subject
end

这假设 subject 不应该是哈希。

也许不是最佳答案,但您可以尝试 keyword argument :

def my_method(subject: nil, **options)
  [ subject, options ]
end

然后

my_method(subject: {foo: 'foo'})

=> [{:foo=>"foo"}, {}]

备选方案:

您可以使用

my_method({foo: 'foo'}, {})

看,你有 **options 作为没有任何默认值的参数,第一个参数有默认值。所以理解以下 单参数案例 ,

每当传递单个参数时,都会尝试将其分配给第二个参数(因为第一个参数默认为 nil)& 如果由于类型不匹配而失败,则将其分配给第一个参数。这就是 my_method(4) 的工作原理。

现在假设你有一个参数作为散列传递,它匹配分配给第二个参数然后它当然被分配给第二个参数并且第一个设置为默认值 nil。

如果你想让它工作,那么你可以做以下事情,

> my_method({sd: 4}, {})
 => [{:sd=>4}, {}]

或者您可以在传递时提供参数名称,

> my_method(subject: {sd: 4})
 => [{:sd=>4}, {}]