Ruby 2.6 で Hash#to_h が便利になった


はじめに

2018/11/06 (火) に Ruby 2.6.0-preview3 がリリースされました。Ruby 2.6.0 で Hash#to_h をブロック付きで呼んだ場合の挙動が新しく追加されていたのでご紹介します。

Hash#to_h について

例として Hash のそれぞれのキーと値に同じ処理を施したい場合、例えば

{ a: 1, b: 2, c: 3 }

{ A: 1, B: 4, C: 9 }

に更新したい場合を想定します。

従来であれば Enumerable#map と Array#to_h を使って

# Ruby 2.5.3 or Ruby 2.6.0-preview3
{ a: 1, b: 2, c: 3 }.map { |k, v| [k.upcase, v ** 2] }.to_h
#=> {:A=>1, :B=>4, :C=>9}

と書けました。Enumerable#map の返り値が Hash オブジェクトではなく Array オブジェクトなので、再度 Hash オブジェクトに変換する必要がありました。

ところが、Ruby 2.6.0 は同じことを Hash#to_h だけで行えるようになりました。

# Ruby 2.6.0-preview3
{ a: 1, b: 2, c: 3 }.to_h { |k, v| [k.upcase, v ** 2] }
#=> {:A=>1, :B=>4, :C=>9}

なお、Ruby 2.5.3 では Hash#to_h をブロック付きで呼んだ場合の挙動が特に定義されていないので、ただレシーバを返すだけです。Hash#to_h はもともとダックタイピングのためだけに用意されたメソッドなのでしょうね。

# Ruby 2.5.3
{ a: 1, b: 2, c: 3 }.to_h { |k, v| [k.upcase, v ** 2] }
#=> {:a=>1, :b=>2, :c=>3}

地味ですが、またひとつ便利になりました