よしかわーるど

プログラミングで世界を変える

2018-09-24

Rubyを学ぶ 4日目

制御構造

前回の記事

Ruby を学ぶ 3 日目

if 文

条件分岐でよく使われる if 文を Ruby で書く。

if 条件A
  # 条件Aが真だった場合の処理
elsif 条件B
  # 条件Bが真だった場合の処理
elsif 条件C
  # 条件Cが真だった場合の処理
else
  # それ以外の条件の処理
end

条件を複数指定する場合は else if や elseif ではなく、elsif であるので注意。

「if 文が戻り値を返す」という性質を利用して、次のように if 文の戻り値を変数に代入することも出来ます。

country = 'italy'

# if文の戻り値を変数に代入する
greeeting =
  if country == 'japan'
    'こんにちは'
  elsif country == 'us'
    'Hello'
  elsif country == 'italy'
    'ciao'
  else
    '???'
  end

greeting #=> "ciao"

unless

Rubyにはifと反対の意味を持つunlessがあります。何が反対なのかというと、条件式が偽になった場合だけ処理を実行する点です。if文で否定の条件を書いているときは、unless文に書き換えられます。

例えば、次のようなコードがあります。

status = 'error'
if status != 'ok'
  '何か異常があります'
end
#=> '何か異常があります'

case

複数の条件を指定する場合は、elsifを重ねるよりもcase文で書いたほうがシンプルになります。

country = 'italy'

case country
when 'japan'
  'こんにちは'
when 'us'
  'Hello'
when 'italy'
  'ciao'
else
  '???'
end
#=> "ciao"

Rubyのcase文ではwehn節に複数の値を指定し、どれかに一致すれば処理を実行する、という条件分岐を書くことが出来ます。

# when節に複数の値を指定する
country = 'アメリカ'

case country
when 'japan', '日本'
  'こんにちは'
when 'us', 'アメリカ'
  'Hello'
when 'italy', 'イタリア'
  'ciao'
else
  '???'
end
#=> "Hello"

if文と同様、case文も最後に評価された式を戻り値として返すため、case文の結果を変数に入れることが可能です。

country = 'italy'

message =
  case country
  when 'japan'
    'こんにちは'
  when 'us'
    'Hello'
  when 'italy'
    'ciao'
  else
    '???'
  end

message#=> "ciao"

when節の後ろにはthenを入れることが出来ます。thenを入れると次のようにwhen節とその条件が真だった場合の処理を1行で書くことが出来ますが、使用頻度はそれほど高くありません。

country = 'italy'

case country
when 'japan' then 'こんにちは'
when 'us' then 'Hello'
when 'italy' then 'ciao'
else '???'
end
#=> "ciao"

while

プログラミングでよく使われるwhileについて触れます。

a = []
while a.size < 5
  a << 1
end
a #=> [1, 1, 1, 1, 1]

条件式の後ろにdoを入れると1行で書くことも出来ます。

a = []
while a.size < 5 do a << 1 end
a #=> [1, 1, 1, 1, 1]

しかし、1行で書くのであれば修飾子としてwhile文を後ろにおいたほうがスッキリ書けます。

a = []
a << 1 while a.size < 5
a #=> [1, 1, 1, 1, 1]

until

while文の反対で、条件が偽である間、処理を繰り返すutil文もあります。

a = [10, 20, 30, 40, 50]
until a.size <= 3
  a.delete_at(-1)
end
a #=> [10, 20, 30]

for

配列やハッシュはfor文で繰り返し処理することも出来ます。

numbers = [1, 2, 3, 4]
sum = 0
for n in numbers
  sum += n
end
sum #=> 10

とはいえ、上のfor文は実質的にはeachメソッドを使った次のコードとほぼ同じです。Rubyのプログラムでは通常、for文よりもeachメソッドを使います。

numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n
  sum += n
end
sum #=> 10

break

breakを使うと、繰り返し処理を脱出することが出来ます、次はeachメソッドとbreakを組み合わせるコード例です。

# shuffleメソッドで配列の要素をランダムに並び替える
numbers = [1, 2, 3, 4, 5].shuffle
numbers.each do |n|
  puts n
  # 5が出たら繰り返しを脱出する
  break if n == 5
end

next

繰り返し処理を途中で中断し、次の繰り返し処理に進める場合はnextを使います。

numbers = [1, 2, 3, 4, 5]
numbers.each do |n|
  # 偶数であれば中断して次の繰り返し処理に進む
  next id n.even?
  puts n
end
#=> 1
#   3
#   5

redo

繰り返し処理をやり直したい場合はredoを使います。ここでいう「やりなおし」は初回からやりなおすのではなく、その回の繰り返し処理の最初に戻る、という意味です。

foods = ['ピーマン', 'トマト', 'セロリ']
foods.each do |food|
  print "#{food}は好きですか? => "
  # sampleは配列からランダムに1要素を取得するメソッド
  answer = ['はい', 'いいえ'].sample
  puts answer

  # はいと答えなければもう一度聞き直す
  redo unless answer == 'はい'
end

retry

例外発生時にもう一度処理をやり直すretry文

retry_count = 0
begin
  puts '処理を開始します。'
  # わざと例外を発生させる
  1 / 0
rescue
  retry_count += 1
  if retry_count <= 3
    puts "retryします。(#{retry_count}回目)"
    retry
  else
    puts 'retryに失敗しました。'
  end
end
# 処理を開始します。
# retryします。(1回目)
# 処理を開始します。
# retryします。(2回目)
# 処理を開始します。
# retryします。(3回目)
# 処理を開始します。
# retryに失敗しました。

raise

def currency_of(country)
  case country
  when :japan
    'yen'
  when :us
    'dollar'
  when :india
    'rupee'
  else
    # 意図的に例外を発生させる
    raise "無効な国名です。#{country}"
  end
end

currency_of(:japan) #=> "japan"
currency_of(:italy) #=> RuntimeError: 無効な国名です。italy

begin

begin
  a << 1
end while false
a #=> [1]

次回の記事

Ruby を学ぶ 5 日目