先日、業務の中でネストしたハッシュが特定のキーに値を持っているか、判定する処理を書きたいときがありました。
こんなときは[]ではなくdigメソッドを使おう!という話。
hash = { "A" => { "x" => "obj1", "y" => "obj2" }, "B" => { "z" => "obj3" } }
要素は、例えば、次のように指定します
hash["A"]["x"]
# => "obj1"
しかし存在しないキーの場合だと、
hash["A"]["z"]
# => nil
のように常になってほしい。
しかしながら、一番外側のキーの時点で存在しないキーを指定すると
hash["C"]["z"]
# NoMethodError: undefined method `[]' for nil:NilClass
# from (pry):89:in `<main>'
nilエラーが出てしまいます。
原因はおわかりのように
hash["C"] # =>nil
に対して["z"]を適用しているから。
nilが返った時点でハッシュでなくなっているため、nilに対して[]を適応しても、「そんなメソッド知りませんがな」となるわけですね。
そこで[]ではなくdigメソッドに置き換えます。
hash.dig("C", "z")
# => nil
どこかの時点で見つからなければnilを返し、見つかれば格納された値を返します。
hash.dig("A", "x")
# => "obj1"
hash.dig("A", "z")
# => nil
これでエラーが返ることなく検索を終えることができます。
digの中身を動的に変更したいときは、
ary = []
ary << "C"
ary << "z"
ary
# => ["C", "z"]
みたいに配列にしてやった上で
hash.dig(*ary)
と書けば長さも値も変幻自在です。
(*を配列に接頭してやると、展開して渡してくれます)
ハッシュの検索結果によってif分岐するようなコードを書きたかったので、エラーが返らないのであれば無事目的を達成できますね。
んまあ、digメソッドの存在を知ったときにはもう、別の妥協案でプルリクだして、マージしちゃってましたけどね😅