使用可选的第一个哈希参数和keyword_args的奇数方法行为
我有以下方法:
def test(first_param = nil, keyword_arg: nil) puts "first_param: #{first_param}" puts "keyword_arg: #{keyword_arg}" end
以下所有调用都按我的预期执行:
test(:something) #=> first_param: something # keyword_arg: test(nil, keyword_arg: :keyword_arg) #=> first_param: # keyword_arg: keyword_arg test({ first_param: :is_a_hash }, keyword_arg: :is_still_working) #=> first_param: {:first_param=>:is_a_hash} # keyword_arg: is_still_working
但是省略可选的keyword_arg
并将散列作为第一个参数传递给我一个错误:
test(first_param: :is_a_hash) #=> test.rb:1:in `test': unknown keyword: first_param (ArgumentError) # from test.rb:12:in `'
我希望它将first_param
设置为{ first_param: :is_hash }
并将keyword_arg
为nil
。
它似乎将每个哈希解释为关键字arg:
test(keyword_arg: :should_be_first_param) #=> first_param: # keyword_arg: should_be_first_param
这应该将first_param
设置为{ keyword_arg: :should_be_first_param }
,在我看来将keyword_arg
{ keyword_arg: :should_be_first_param }
nil
。
这是解析器错误还是预期的行为? 测试ruby 2.3.0和2.2.4。
编辑:使第一个参数成为必需的 ,一切都像我期望的那样:
def test_mandatory(first_param, keyword_arg: nil) puts "first_param: #{first_param}" puts "keyword_arg: #{keyword_arg}" end test_mandatory(first_param: :is_a_hash) #=> first_param: {:first_param=>:is_a_hash} # keyword_arg: test_mandatory(keyword_arg: :should_be_first_param) #=> first_param: {:keyword_arg=>:should_be_first_param} # keyword_arg:
我希望使参数可选不会改变参数解析的方式。
我在bugs.ruby-lang.org上打开了一个问题 ,然后开发人员可以清楚它是否是这样的或者是kword args的副作用。
根据Marc-Andre Lafortune的回复,这是预期的 :
这种行为可能令人惊讶,但这是故意的。
归结为优先考虑首先填充关键字参数而不是填充未命名的参数。 这实际上是唯一可行的方法。 除其他外,请考虑以下示例:
def foo(*rest, bar: 42) end
如果我们不首先确定命名参数的优先级,那么在这个例子中根本没有办法为bar指定值!
所以Ruby检查:
- 在填写所有强制性未命名参数之后
- 如果最后剩下的参数是散列的
- 它的所有键都是符号
- 并且调用的方法使用关键字参数
=>然后该参数用于关键字参数。
注意键是符号的要求。 如果您使用一些不是符号的键传递哈希,这会产生更多的惊喜:
def foo(a = nil, b: nil) pa, b end foo(:b => 42) # => nil, 42 foo('b' => 42) # => {"b" => 42}, nil