1
0

More than 3 years have passed since last update.

Ruby 2.7 のキーワード引数と配列展開と send を組み合わせると warning が出ない

Posted at

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

Links

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0