Ruby 2.7 でキーワード引数とハッシュが自動変換されるときに警告が出るようになった。キーワード引数は def m(a:); end
みたいに引数に名前をつけて渡す機能。仮引数に **
をつけるとキーワード引数の残りをハッシュとして受け取れる。
# kw1 は必須のキーワード引数、 kwrest はkw1 以外のキーワードがハッシュ形式で受け取れる。
def a_method(kw1: 1, **kwrest)
puts "kw1: #{kw1}"
puts "kwrest: #{kwrest}"
end
a_method(kw1: 42, kw2: 4242)
# kw1: 42
# kwrest: { kw2: 4242 }
キーワードはどうみてもハッシュだからハッシュだと思っていたんだけど、 2.7 でハッシュとキーワードを区別するようになった。{}
をつけて明示的にハッシュとして渡すとwarningがでて怒られる。
a_method({ kw1: 42, kw2: 4242 })
# (irb):5: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
# (irb):1: warning: The called method `a_method' is defined here
これは **
(double splats)演算子でハッシュをキーワードに展開することを明示しつつメソッドを呼び出すと回避できる。
a_method(**{ kw1: 42, kw2: 4242 })
**
は *
で配列を展開するイメージからの連想なのかなと連想し、*
で配列展開しつつさらにキーワードを渡してみようとやってみたけどできなかった。展開される前にハッシュをアイテムとする配列に評価されるからまあそうなるかな、という感じ。
# * で配列を展開しつつキーワードを渡したいけどできなかった
a_method(*[kw1: 42]) # => warning
a_method(*[{ kw1: 42 }]) # => warning
a_method(*[**{ kw1: 42 }]) # => warning
だけど、 send
と組み合わせると warning がでなくなる。 send
の二つ目以降の引数は特別扱いされる?
send(:a_method, kw1: 1) # => no warning
send(:a_method, { kw1: 1 }) # => warning
send(:a_method, *[kw1: 1]) # => no warning
send(:a_method, *[{ kw1: 1 }]) # => warning
send(:a_method, *[**{ kw1: 1 }]) # => no warning
# 変数に受けるとだめ。
args = [kw1: 1]
send(:a_method, *args) # => warning