我想将一个可选参数(任何数据类型,甚至是哈希)后跟关键字参数列表(可以为空)传递给方法。
这就是我得到的:
def my_method(subject = nil, **options)
[subject, options]
end
在以下情况下,方法输出符合预期:
无
my_method() # => [nil, {}]
一个主题
my_method('foo') # => ["foo", {}]
带有选项的文字主题
my_method('foo', bar: 'bar') # => ["foo", {:bar=>"bar"}]
作为主题的
Hash
,有选项my_method({foo: 'foo'}, bar: 'bar') # => [{:foo=>"foo"}, {:bar=>"bar"}]
没有主题,只有选项
my_method(bar: 'bar') # => [nil, {:bar=>"bar"}]
当将Hash
作为主题传递且没有选项时,期望的结果是:
my_method({foo: 'foo'})
# => [{:foo=>"foo"}, {}]
但我得到以下内容;我没有得到正确的主题:
my_method({foo: 'foo'})
# => [nil, {:foo=>"foo"}]
my_method(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}, {}]
据我所知,这是Ruby传递参数方式的限制。它无法区分my_method({foo: 'foo'})
和my_method(foo: 'foo')
为什么不用这个来破解它呢?
if subject.is_a?(Hash) && options.empty?
subject, options = nil, subject
end
这假设subject
不应该是一个哈希值。
也许不是最好的答案,但你可以尝试使用关键字参数:
def my_method(subject: nil, **options)
[ subject, options ]
end
然后
my_method(subject: {foo: 'foo'})
=> [{:foo=>"foo"}, {}]
另类:
您可以使用
my_method({foo: 'foo'}, {})