LoginSignup
32
23

More than 5 years have passed since last update.

Ruby の Hash#fetch が便利

Posted at

Hash#fetch は便利なメソッドです。基本的には Hash#[] と同じ動作をしますが、キーが存在しない場合の動作が異なります。

key が存在しない場合は例外が発生する

Hash#[] では指定した key が存在しない場合は nil を返します。

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user[:name]  #=> "Yamada Tarou"
p user[:email] #=> nil

しかし、Hash#fetch メソッドでは指定した key が存在しない場合は例外が発生します。これは Hash.new(0) のようにハッシュにデフォルト値を設定していても発生します。

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user.fetch(:name)  #=> "Yamada Tarou"
p user.fetch(:email) #=> `fetch': key not found: :email (KeyError)

例外が発生するため、key のスペルミスによるバグが発生しなくなります。

デフォルト値を指定することが可能

Hash#fetch は第二引数にデフォルト値を指定することが可能で、key が存在しない場合はこのデフォルト値を返します。

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user.fetch(:name)                       #=> "Yamada Tarou"
p user.fetch(:email, "dummy@example.com") #=> "dummy@example.com"

Hash#[] でも似たような操作を書くことは可能ですが

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user[:admin] || true     #=> true
p user.fetch(:admin, true) #=> true

指定した key の値が nilfalse の場合に期待した動作にならない場合があるので注意が必要です。

user = {
  id: 1,
  name: "Yamada Tarou",
  admin: false
}

p user[:admin] || true     #=> true
p user.fetch(:admin, true) #=> false

ブロックを受け取れる

また、Hash#fetch ではブロックを渡すことも可能で、キーが存在しない場合はそのブロックの戻り値を返します。ブロック引数には指定した key の値が入ります。

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user.fetch(:name)                       #=> "Yamada Tarou"
p user.fetch(:email) { |key|
  "#{key} not found"                      #=> "email not found"
}

これは第二引数に Proc オブジェクトを渡すことで同様のことが可能です。

default = -> (key) {
  "#{key} not found"
}

user = {
  id: 1,
  name: "Yamada Tarou"
}

p user.fetch(:name)            #=> "Yamada Tarou"
p user.fetch(:email, &default) #=> "email not found"

参考サイト

32
23
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
32
23