すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Ruby

【Ruby】 case whenによる条件分岐を基礎から応用まで学ぼう

ぴっかちゃん
ぴっかちゃん

caseは1つの式に対する一致判定によって処理が分岐される制御構造のひとつです。caseのあとに記述する式とwhen節のあとに記述する各式の値(評価結果)を比較します。

caseは、caseのあとに記述した式とwhen節に記述した式の値(評価結果)を上から順番に比較し、一致すればそのwhen節の本体に記述する処理が実行されます。

caseの文法
1
2
3
4
5
6
7
8
case 0 #この式の値とwhen節に記述される各式の値が比較される
when 1 then # 式0と式1の評価結果が一致した場合の処理(when節本体) when 2 then # 式0と式2の評価結果が一致した場合の処理(when節本体) else # どの式とも一致しなかった場合の処理 end

例えば、以下のコードでは対象の式であるbreakfastの値('ご飯')と一致するのは、2番目のwhen節の式の値('ご飯')なので'ご飯派です。'が出力されます。

breakfast.rb | caseのサンプルコード
1
2
3
4
5
6
7
8
9
10
11
breakfast = 'ご飯'

case breakfast #式の値(評価結果)は'ご飯'
when 'パン' then puts 'パン派です。'
when 'ご飯' then
puts 'ご飯派です。' # このwhen節本体が評価される else puts 'パン派でもご飯派でもありません' end
#=> ご飯派です。

この記事では、caseの使い方を基礎から応用まで段階的に解説しているので、初めての方も1つ1つ整理しながら学ぶことができます。

caseの基本的な使い方

この章では、caseの書き方や処理の流れ、どんな場面で使用すれば良いのかなど基本的な部分を解説します。

基本構文

caseは、以下のようにcase~endまでが範囲になります。

case文の文法
1
2
3
4
5
6
7
8
case 0
when 1 then
  # 式0と式1の評価結果が一致した場合の処理(when節本体)
when 2 then
  # 式0と式2の評価結果が一致した場合の処理(when節本体)
else
  # どの式とも一致しなかった場合の処理
end
  • case - 対象の式を記述します。
  • when - 比較する式、when節本体には一致した際の処理を記述します。
  • else - どれも一致しなかった場合の処理を記述します。

when 式1 thenとは「式0式1の値が一致する場合にthen以下の式を評価する」という意味になります。when節、else節のインデントはcaseに揃えます。

※thenは省略することができます。(この章以降はthenを省略します。)

処理の流れ

記事の冒頭では、caseについて下記のように記述しました。

caseは、caseのあとに記述した式とwhen節に記述した式の値(評価結果)を上から順番に比較し、一致すればそのwhen節の本体に記述する処理が実行されます。

この処理の流れをサンプルコードで表すと、以下のような順番になります。

caseの処理の流れ

  1. breakfastの式が評価される。('ご飯'という結果になる)
  2. breakfastの'ご飯''パン'を比較する。一致しないので次のwhen節へ
  3. breakfastの'ご飯'とwhen節の'ご飯'を比較する。一致するのでwhen節本体へ
  4. when節本体の式が評価されて、ご飯派です。が出力される

上記の「1. breakfastの式が評価される。」とありますが、以下の動画のように式(breakfast)を実行して値を得ることを「評価」といい、値('ご飯')が評価の結果になります。

式の評価結果

つまり、caseはcaseの式(breakfast)の評価結果('ご飯')とwhen節に記述される各式の値(評価結果)を上から順番に比較して一致するか判定しているのです。

ポイント
  1. 式を実行して値を得ることを「評価」という
  2. 上記の値は「評価の結果」という

※記事では直感的に理解できるように「式の値」としているが、厳密に記述すると「式を評価した結果」になる

全ての式に一致しない場合

caseの式の値がどのwhen節の式の値にも一致しない場合は、else節に記述した処理が実行されます。

例えばbreakfastに'スムージー'を代入した場合は、以下の通りになります。

breakfast.rb | breakfastにスムージーを代入した場合
1
2
3
4
5
6
7
8
9
10
11
breakfast = 'スムージー' # ご飯からスムージーへ変更
case breakfast when 'パン' puts 'パン派です。' when 'ご飯' puts 'ご飯派です。' else
puts 'パン派でもご飯派でもありません'
end
#=> パン派でもご飯派でもありません

breakfastは、when節の'パン'にも'ご飯'にも一致しないのでelse節の処理が実行されて、パン派でもご飯派でもありませんが出力されます。

ここまでの処理の流れを一旦整理しよう!
  1. caseのあとに記述した式の値(評価結果)とwhen節の値を比較する
  2. 値が一致すれば、when節本体に記述する処理が実行される
  3. どのwhen節の値にも一致しなければelse節の処理が実行される

caseの返り値

caseの返り値は、最後に評価した式の結果を返します。

以下のサンプルコードでは、ハイライトされた'ご飯派です。'の式が最後に評価される式となり、式の結果がcaseの返り値になります。

breakfast.rb | caseのサンプルコード
1
2
3
4
5
6
7
8
9
10
11
breakfast = 'ご飯'

case breakfast
when 'パン'
  'パン派です。'
when 'ご飯'
'ご飯派です。' # caseの返り値になる
else 'パン派でもご飯派でもありません' end #=> ご飯派です。

このようにcaseを実行すると式の結果を返り値として得られるので、以下のサンプルコードのようにresultの変数にcaseを代入して利用することもできます。

breakfast.rb | caseを変数に代入する場合
1
2
3
4
5
6
7
8
9
10
11
12
breakfast = 'ご飯'

result = case breakfast
when 'パン' 'パン派です。' when 'ご飯' 'ご飯派です。' else 'パン派でもご飯派でもありません' end puts result #=>ご飯派です。

caseをifに置き換えた場合

caseで記述されたコードは、ifに置き換えることができます。
以下は、caseのサンプルコードです。

breakfast.rb | caseのサンプルコード
1
2
3
4
5
6
7
8
9
10
11
breakfast = 'ご飯'

case breakfast
when 'パン'
  puts 'パン派です。'
when 'ご飯'
  puts 'ご飯派です。' 
else
  puts 'パン派でもご飯派でもありません'
end
#=> ご飯派です。

上記のコードをifに置き換えると、以下の通りになります。

breakfast.rb | 上記のコードをifに置き換えた場合
1
2
3
4
5
6
7
8
9
10
breakfast = 'ご飯'

if breakfast === 'パン'
puts 'パン派です。'
elsif breakfast === 'ご飯'
puts 'ご飯派です。' else puts 'パン派でもご飯派でもありません' end #=> ご飯派です。

上記のコードのようにcaseからifへ置き換えることができましが、caseと違ってifの方は各式にbreakfastを記述して比較させなければいけませんね。

さらにcaseとifのどちらでもこの条件のコードはかけてしまうので「結局どちらを使えば良いのか?」と疑問を持つかと思います。その疑問点は、次の章で解決していきます。

caseを使用する場面とは?

前の章では、caseで記述されたサンプルコードをifに置き換えることができましたね。

どちらを使えば良いか迷うかもしれませんが、1つのデータ(式の評価結果)に対して複数の値をチェックして処理を分けたい場面では、caseを使った方が可読性があがります。

なぜならifの場合は条件式を自由に指定することができるので、いろいろなパターンを想定してコードを読む必要があるからです。例えば、以下のようにbreakfastの値の一致と関係ない条件式が含まれる可能性も考慮する必要があります。

breakfast.rb | ifを使用した場合のサンプルコード
1
2
3
4
5
6
7
8
breakfast = 'ご飯'

if breakfast.empty? # breakfastが空かチェックする
puts '朝食を用意してません' else puts '朝食を用意しています。' end #=>朝食を用意しています。

上記のようにifを使う場合はbreakfastの値の一致とは関係のない条件式も自由に設定できるので、どんな条件式が設定されているか当たりも付けられず可読性が下がりますね。

しかしcaseの場合は、以下のようにcaseの式と各when節の値が一致するか読むだけでよいのでifに比べてどんな条件式か当たりをつけられて可読性が上がります。

breakfast.rb | caseを使用した場合のサンプルコード
1
2
3
4
5
6
7
8
9
10
11
breakfast = 'ご飯'
case breakfast
when 'パン'
puts 'パン派です。'
when 'ご飯'
puts 'ご飯派です。' else puts 'パン派でもご飯派でもありません' end #=> ご飯派です。

このように1つのデータに対して複数の値をチェックして処理を分ける場合には、ifではなくcaseを使用するようにしましょう。

case文の応用的な使い方

この章では、基礎から発展したcaseの応用的な使い方や便利な使い方を解説します。

複数の値を指定する方法

when節には、カンマで区切って複数の値(式)を指定することもできます。

caseの文法(複数の値を指定する場合)
1
2
3
4
5
6
7
8
case 0
when 1, 2
# 式0と式1 or 式0と式2の評価結果が一致した場合の処理 when 3, 4 # 式0と式3 or 式0と式4の評価結果が一致した場合の処理 else # どの式とも一致しなかった場合の処理 end

上記のwhen 式1, 式2は「式0式1の値が一致するか、もしくは式0式2の値が一致する場合」という意味になります。when節の式は上から順に(そして左から順に)式0と一致するか比較されて、一致した時点でwhen節本体が評価されます。

上記のcaseのコードは、以下のifと大体同じです。

caseの文法(複数の値を指定する場合)をifに書き直した場合
1
2
3
4
5
6
7
if 1 === 0 or 2 === 0
   # 式0と式1 or 式0と式2の評価結果が一致した場合の処理
elsif 3 === 0 or 4 === 0
   # 式0と式3 or 式0と式4の評価結果が一致した場合の処理
else
   # どの式とも一致しなかった場合の処理
end

それでは、when節に複数の値を指定する場合をサンプルコードでみていきましょう。

以下のサンプルコードでは、numの値に対して各when節の値を比較しています。最初のwhen節に複数の値が指定されていますね。

sample.rb | 複数の値を指定する場合のサンプルコード
1
2
3
4
5
6
7
8
9
10
11
num = 2

case num
when 1, 2, 3
puts '値は1~3のどれかです。' # このwhen節本体が評価される when 4 puts '値は4です。' else puts '値は1~4ではありません。' end #=>値は1~3のどれかです。

処理の流れは、以下の通りです。

  1. caseに指定したnumの式が評価される。(2という結果になる)
  2. numの2と最初のwhen節の1が比較される。
  3. 一致しなかったので、numの2とwhen節の2が比較される。(一致)
  4. 上記が一致したので、when節本体が評価される(値は1~3のどれかです。を出力)

when 1, 2, 3とありましたがwhen節に複数の値を指定した場合には、左から順番にnumの値と比較して一致した時点で処理が実行されるので、3は比較されずにwhen節本体の処理が実行されています。

配列を指定する方法

when節にはwhen *配列と指定することで配列を使用することができます。

先ほどwhen節に複数の値を指定する方法を解説しましたが、when節に配列を使用することで置き換えることができます。

sample.rb | 複数の値を指定する場合
1
2
3
4
5
6
7
8
9
10
11
num = 2

case num
when 1, 2, 3
puts '値は1~3のどれかです。' # このwhen節本体が評価される when 4 puts '値は4です。' else puts '値は1~4ではありません。' end #=>値は1~3のどれかです。
sample.rb | 配列を指定する場合
1
2
3
4
5
6
7
8
9
10
11
12
ary = [1,2,3]
num = 2 case num
when *ary
puts '値は1~3のどれかです。' when 4 puts '値は4です。' else puts '値は1~4ではありません。' end #=>値は1~3のどれかです。

上記のwhen *aryのように配列の前に*をつけることで、配列展開されてnumと比較ができるようになります。

範囲オブジェクトを指定する方法

when節には以下のような範囲オブジェクトを指定することができます。

範囲オブジェクトのサンプル
1
2
1 .. 5 # 1以上5以下(5を含む)
1 ... 5 # 1以上5未満(5を含まない)

例えば各when節に範囲オブジェクトを以下のコードのように指定することで、年齢別に処理を分けることができます。

sample.rb | 範囲オブジェクトを指定する場合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
age = 6 

case age
when 0 .. 2 #0才以上2才以下の者
puts "入場料金は無料です。"
when 3 .. 6 #3才以上6才以下の者
puts "入場料金は500円です。"
when 7 .. 12 #7才以上12才以下の者
puts "入場料金は800円です。"
when 13 .. 18 #13才以上18才以下の者
puts "入場料金は1,500円です。" else puts "入場料金は1,800円です。" end #=>入場料金は500円です。

ageには6が代入されているので、入場料金は500円です。が出力されます。

caseの「式」にメソッドを使用する場合

caseの式には変数だけではなく、メソッドも使用することが出来ます。
メソッドには、以下の文字列の文字数を返すlengthメソッドを使用していきます。

irb | lengthメソッドを使用した場合
1
2
3
4
irb(main):001:0> str = '私の名前は山田花子です。'
=> "私の名前は山田花子です。"
irb(main):002:0> str.length
=> 12

以下のコードのハイライト部分のように指定することで、str.lengthの結果に対して各when節の値を比較することができます。

sample.rb | caseにメソッドを使用する場合
1
2
3
4
5
6
7
8
9
10
str = '私の名前は山田花子です。'

case str.length
when 1..3 '文字数不足です。' when 4..10 '設定した文字数の範囲内です。' when 10..nil # 10以上で上限なし '文字数オーバーです。' # => '文字数オーバーです。'

str.lengthの結果は12になるのでwhen 10..nilの式本体が実行されます。

このようにメソッドを使用することで、メソッドの実行結果でwhen節の値をチェックすることができるので実用性が広がりますね。

case の「式」を省略した場合

caseの式を省略した場合は、以下のコードのようにwhen節の式が偽ではない最初の式が評価されます。when節には2箇所にtrueを指定していますが、処理が実行されるのは最初のtrueの方です。

sample.rb | caseの式を省略した場合
1
2
3
4
5
6
7
8
9
case
when false
  puts "falseは偽なので実行されません。"
when true
puts "trueは真なので実行されます。" when true puts "trueは真ですが、最初ではないので実行されません。" end #=>trueは真なので実行されます。

上記のコードのtruefalseがイメージしづらいという方は、以下のコードを参考にしてください。

sample.rb | caseの式を省略した場合
1
2
3
4
5
6
7
8
9
10
11
price = 100

case
when price < 10
  puts "式は偽なので実行されません。"
when price == 100
puts "式は真なので実行されます。" when price == 100 puts "式は真ですが、最初ではないので実行されません。" end #=>式は真なので実行されます。

irbで試すとわかりますが、上記のwhen節の式は以下のようにtruefaseをそれぞれ返します。

irb | priceを比較した場合
1
2
3
4
5
6
irb(main):001:0> price = 100
=> 100
irb(main):002:0> price < 10
=> false
irb(main):003:0> price == 100
=> true

caseを省略した場合は、when節の偽ではない最初の式が評価されるのでハイライトされているprice == 100の式本体が実行されるのです。

sample.rb | caseの式を省略した場合
1
2
3
4
5
6
7
8
9
10
11
price = 100

case
when price < 10
  puts "式は偽なので実行されません。"
when price == 100
puts "式は真なので実行されます。" when price == 100 puts "式は真ですが、最初ではないので実行されません。" end #=>式は真なので実行されます。
ポイント

caseの式を省略した場合は、when節の式が偽ではない最初の式が評価されます。

classによって処理を変える方法

when節には、以下のコードのようにclassを指定することもできます。

sample.rb | classによって処理を変える方法
1
2
3
4
5
6
7
8
9
10
11
12
13
obj = [1,2,3]

case obj
when String
  puts 'classはStringです。'
when Array
  puts 'classはArrayです。'
when Hash
  puts 'classはHashです。'
else
  puts 'classはString、Array、Hash以外です。'
end
#=>classはArrayです。

classによって実行する処理を変えたい場合に便利ですね。

制御構造の条件分岐まとめ

Rubyの条件分岐は、以下の表の通りです。

条件分岐 説明 リンク
case 1つの式に対する一致判定によって処理が分岐される
if 真偽値で条件を分岐することができる
(真の時にthen以下の式を評価)
ifの使い方
unless 真偽値で条件を分岐することができる
(偽の時にthen以下の式を評価)
unlessの使い方

Rubyの制御構造の条件分岐について、もっと深く理解したい方はこちらの参考書で学びましょう。

この記事のまとめ

  • caseは1つの式に対する一致判定によって処理が分岐される
  • caseの式とwhen節の式の評価結果が一致すると、when節本体の処理が実行される
  • どの式にも一致しない場合は、else節の処理が実行される