【Ruby】ハッシュのtry(try hash)をdigで書き換える

Ruby

「オブジェクトが存在しないケースを考慮し、オブジェクトのプロパティを参照する」、このような時にtry hashが活躍します。
try hashはdigで書き換えられます。今回はtry hashとdigの概要と、書き換えの具体例について紹介します。

try hashについて

try hashとはハッシュに対してtryを実行することです。
try hashはハッシュが存在していればプロパティの値、存在していなければnilを返します。try hashの記述方法はハッシュ.try(:[], 'プロパティ名')です。

ハッシュが存在していない場合、通常ですとプロパティ参照時にNoMethodErrorの例外が発生しますが、try hashを利用することでnilが返されます。

### nilオブジェクトのプロパティを参照する(通常の参照)
> user = nil
> user[:name]
# NoMethodError: undefined method `name' for nil:NilClass

### nilオブジェクトのプロパティを参照する(try hashによる参照)
> user = nil
> user.try(:[], :name)
=> nil

つまり、try hashはハッシュ(オブジェクト)が存在しないケースを考慮したプロパティの参照方法です。

digについて

digはオブジェクトのプロパティを再帰的に参照するメソッドです。dig(キー名,...)のようにキー名を複数引数にすることで再帰的に参照が実行されます。オブジェクトがnilの場合はnilを返します。digはRuby 2.3で導入されました。

digの具体例は以下の通りです。

### userオブジェクトに存在するaddressオブジェクトのprefプロパティを参照する
> user = { address: { pref: 'Tokyo' } }
> user.dig(:address, :pref)
=> "Tokyo"

### userオブジェクトに存在するaddressオブジェクトのprefプロパティを参照する(addressにprefが存在しない場合)
> user = { address: {} }
> user.dig(:address, :pref)
=> nil

digにはHash#digだけでなくArray#digもあるため、ハッシュと配列が組み合わされたオブジェクトにもdigが利用できます。

### userのfavarite_foodsの先頭を取り出す
> user = { favorite_foods: ["Sushi", "Sukiyaki"] }
> user.dig(:favorite_foods, 0)
=> "Sushi"

try hashをdigで書き換える具体例

try hashはdigで書き換えられます。以下では具体例について紹介します。

try hashからdigへの書き換えの基本形

「userオブジェクトが存在していないケースを考慮に入れ、nameプロパティを参照する」をtry hashで書くと以下のようになります。

### userが存在している場合
> user = {name: 'Suzuki'}
> user.try(:[], :name)
=> "Suzuki"

### userが存在していない場合
> user = nil
> user.try(:[], :name)
=> nil

digで書き換える場合はRubyの&.(ぼっち演算子、Null条件演算子、Safe Navigation Operator)と組み合わせて以下のようになります。

### userが存在している場合
> user = { name: 'Suzuki' }
> user&.dig(:name)
=> "Suzuki"

### userが存在していない場合
> user = nil
> user&.dig(:name)
=> nil

ネストしたハッシュの場合

「userオブジェクトが存在していないケースを考慮に入れ、userのaddressオブジェクトのprefプロパティを参照する」をtry hashで書くと以下のようになります。

### userが存在している場合
> user = { address: { pref: 'Tokyo' } }
> user.try(:[],:address).try(:[],:pref)
=> "Tokyo"

### userが存在していない場合
> user = nil
> user.try(:[],:address).try(:[],:pref)
=> nil

digで書き換えると以下のようになります。

### userが存在している場合
> user = { address: { pref: 'Tokyo' } }
> user&.dig(:address, :pref)
=> "Tokyo"

### userが存在していない場合
> user = nil
> user&.dig(:address, :pref)
=> nil

nilに対するデフォルト値が考慮されている場合

短絡評価(ショートサーキット)を利用することで結果がnilだった場合のデフォルト値を設定できます。
短絡評価とは『左辺を評価した段階で式の結果が決まらない場合のみ右辺を評価する(式の結果が決まった時点で後続の評価をしない)』という評価方法のことをいいます。短絡評価はOR演算子(||)で実現できます。

「userオブジェクトのfavarite_foods一覧(Array)を取得する、userが存在しない場合は空の配列をセットする」をtry hashと短絡評価を組み合わせて書くと以下のようになります。

### userが存在している場合
> user = { favorite_foods: ["Sushi", "Sukiyaki"] }
> user.try(:[], :favorite_foods) || []
=> ["Sushi", "Sukiyaki"]

### userが存在していない場合
> user = nil
> user.try(:[], :favorite_foods) || []
=> []

digで書き換えると以下のようになります。

### userが存在している場合
> user = { favorite_foods: ["Sushi", "Sukiyaki"] }
> user&.dig(:favorite_foods) || []
=> ["Sushi", "Sukiyaki"]

### userが存在していない場合
> user = nil
> user&.dig(:favorite_foods) || []
=> []

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!