webエンジニアの日常

RubyやPython, JSなど、IT関連の記事を書いています

ハッシュにデフォルト値を付けれるって知ってました?!

Effective Rubyの勉強メモです。

Hashクラスのオブジェクトに対して無効キーを渡すとnilが返ってきます。

nilが返ってくることを期待して(利用して)書いたコードもありますが、nilが返ってくるためnilガードで値を設定するコードが増えたり、思わぬところにエラーが起こってしまう可能性もあります。

Hashでは無効キーで参照されたときに返す値がデフォルトでnilになっているからです。

ですが、Hashはnewメソッドの第一引数に値を与えると、無効キーで参照されたときのデフォルト値を変更することができます。

今回はHashのデフォルト値について有用な点、注意点、デフォルト値を与える以外の方法を見ていきたいと思います。

スポンサーリンク

Hashにデフォルト値を設定する

次の構文でHashにデフォルト値を設定することができます。

hash = Hash.new(0)
hash[:missing_key] #=> 0

これを使うことで、用途が決まっている場合に

hash[:age] ||= 0
hash[:age] += 1

のようにnilガードを毎回書く必要がなくなりました。

しかし、注意も必要です。

今回は数字の0をデフォルト値としましたが、空配列だった場合を考えてみます。

hash = Hash.new([])

hash[:missing_key] #=> []

hash[:missing_key] << "apple" #=> ["apple"]

hash.keys

hash[:nothing_key] #=> ["apple"]

Hashのデフォルト値がミュータブルな配列の場合、あとでデフォルト値が変更されてしまうのです。

これは、newメソッドに渡した配列と、無効キーで参照しようとしたときに返される配列が同じアドレスを参照しているためです。

ほとんどの場合にデフォルト値は変更されたくないと思うはずです。

そこで、ブロックを渡す方法があります。

hash = Hash.new{[]}

hash[:missing_key] << "apple" #=> ["apple"]

hash.keys #=> []

hash[:missing_key] #=> []

Hashのnewメソッドにブロックを渡すと、デフォルト値を返すたびにブロック内を実行してくれるので、毎回異なる参照のオブジェクトを返してくれます。

デフォルト値を設定したときの注意点

デフォルト値を設定しなければ、nilが返ることは上でも書きましたが、nilであることを利用して書かれているコードがあると思います。

if hash[:missing_key]
  # キーが無効の場合の処理
end

このようなコードが書いてるにも関わらず、デフォルト値をnil,false以外のオブジェクトに設定してしまうと、上記のコードはうまく動いてくれません。

なので、キーがないことを判定するにはHash#has_key?メソッドを使いましょう。

hash[:a] = 1
hash.has_key?(:a) #=> true
hash.has_key?(:missing_key) #=> false

デフォルト値を使わない方法

一方でデフォルト値を使わずに参照する方法もあります。

それはfetchメソッドを使う方法です。

hash.fetch(:missing_key, []) #=> []

fetchメソッドは第一引数に参照したいキーを、第二引数に無効キーが渡された場合に返すオブジェクトを設定できます。

第二引数を設定しない場合に、無効キーで参照しようとすると例外が発生します。

ハッシュオブジェクト全体にデフォルト値を設定するよりコード量は増えますが、fetchを使った方が安全な場合もあるので覚えておくといいでしょう。

参考

  • Effective Ruby

本シリーズはこの本を勉強しながら進めています。

初心者には難しいと思いますが、知らなかったことばかりで面白いです!

Effective Ruby

Effective Ruby

  • Ruby on Railsアプリケーションプログラミング

Ruby単体よりもRailsを使うためにRubyを勉強される方が多いようです。

1冊Railsのオススメ書籍を載せておきます。

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

  • プロを目指す人のためのRuby入門

言語仕様から開発手法まで、幅広い話題が載っていて、これからRubyを始める方やほかの言語を学んでRubyを勉強したい方にお勧めです!