制御構造

プログラミングの基本である条件分岐・繰り返し・例外処理について説明します。

 

条件分岐

(1)if文

Rubyのif文は次のような構文になります。

if 条件式1 then
#条件式1が真の場合の処理
elsif 条件式2 then
#条件式2が真の場合の処理
else
#条件式1、2がともに偽の場合の処理
end

 「then」は省略しても構いません。また条件式には真偽値(true/false/nil)を返す式を指定します。Rubyでは「真」をfalsenil以外の全て、「偽」をfalseまたはnilとしています。真偽値は比較演算子(>, >=, <, <=, ==, !=など)、真偽値を返すメソッド(empty?zero?など後ろに?が付くもの)、正規表現のマッチングの結果(マッチすればインデックスを返し、マッチしなければnilを返す)などと、論理演算子(&&, ||, !, and, or, not)を組合せて求めます。

 

 <if.rb>

a = 100
b = 200

if a > 100 && b.zero? then
puts "a is greater than 100 and b is 0"
elsif a > 100 then
puts "a is greater than 100 and b is not 0"
elsif a == 100 then
puts "a is equal to 100"
else
puts "a is smaller than 100"
end

 

 <実行結果>

C:\ruby>ruby if.rb
a is equal to 100

 

(2)case文

多分岐を実現する式としてcase文があります。次の構文になります。thenは省略可能です。 

case 対象オブジェクト
when 値1then
#式と値1と一致する場合に行う処理
when 値2then
#式と値2と一致する場合に行う処理
else
#どの値とも一致しなかった場合に行う処理
end

 when節の値を「when 値x, 値y, 値z」のようにカンマで区切って並べることで、そのいずれかの値と一致した場合の処理として記述することもできます。
対象オブジェクトと値とを比較するときは、演算子「===」を用いています。例えば値として範囲オブジェクト「1..5」(1~5の整数)を指定すると、演算子「===」により対象オブジェクトが範囲内に存在するかを確認します。

 

 <case.rb>

banana_num = 5

case banana_num
when 1 then
puts "Price: 20"
when 2,3,4 then
puts "Price: 40"
when 5..8 then
puts "Price: 80"
else
puts "Unacceptable!"
end

 

 <実行結果>

C:\ruby>ruby case.rb
Price: 80

 

 (3)その他の条件分岐

 条件分岐を記述する方法として、他にも次のようなものがあります。

<other_cond_branch.rb>

#条件演算子(三項演算子)
#[構文] 条件式 ? 真の時の値 : 偽の時の値

score = 80
result = score > 70 ? "Pass" : "Failed" #右辺の評価結果をresultに代入
puts result

#unless文 - if文の逆
#[構文]
#unless 条件式 then
# 条件式が偽の時の処理
#else
# 条件式が真の時の処理
#end

puts "-------"
lang = "Ruby"

unless lang == "Ruby" then
puts "#{lang} is not Ruby"
else
puts "Enjoy Ruby totorial"
end

#if修飾子, unless修飾子
#[構文] 真の時の処理 if 条件式
#[構文] 偽の時の処理 unless 条件式

puts "-------"
debug = true
num = 10

puts "num = #{num}" if debug #debugがtrueのときのみ実行

 

 <実行結果>

C:\ruby>ruby other_cond_branch.rb
Pass
-------
Enjoy Ruby totorial
-------
num = 10

 

 

 繰り返し

 Rubyで繰り返し処理を行うメソッドを、繰り返しのタイプ別に紹介します。

(1)決められた回数繰り返し

決められた回数の繰り返しを行うにはtimesメソッドを利用します。

数値.times {|変数|
#処理
}

 変数に0から「数値 - 1」までを順に代入しながら、処理を実行します。|変数|は省略することもできます。


<times.rb>

3.times { 
puts "Hello"
}

3.times { |cnt|
puts "cnt = #{cnt}"
}

 

<実行結果>

C:\ruby>ruby times.rb
Hello
Hello
Hello
cnt = 0
cnt = 1
cnt = 2

 

この他、ループ変数の開始と終了を指定して実行するメソッドとして、upto, downto, stepがあります。

  <upto_downto_step.rb>

puts "upto:"
#numが3から5に1つずつ増加
3.upto(5) {|num|
puts "num = #{num}"
}

puts "downto:"
#numが8から6に1つずつ減少
8.downto(6) {|num|
puts "num = #{num}"
}

puts "step:"
#numが12.3から14.1を超える前まで0.5ずつ増加
12.3.step(14.1, 0.5) {|num|
puts "num = #{num}"
}

 

 <実行結果>

C:\ruby>ruby upto_downto_step.rb
upto:
num = 3
num = 4
num = 5
downto:
num = 8
num = 7
num = 6
step:
num = 12.3
num = 12.8
num = 13.3
num = 13.8

 

 (2)すべての要素に対する繰り返し

配列やハッシュなどのオブジェクトから順に値を取り出して繰り返し処理を実行するときは、eachメソッドやforメソッドを用います。eachの構文は次の通りです。

オブジェクト.each {|要素|
#処理
}


eachのオブジェクトとして範囲オブジェクトも指定できます。範囲オブジェクトとは範囲を表すオブジェクトで、「3..10」や「5…10」のように、範囲の最初と最後を表す数値(または文字列)を指定します。数値または文字の間に、ドットが2つあるときは、両端を含む連続した数値(または文字列)を表し、3つあるときは右端の直前までの数値(または文字列)を表します。


<each.rb>

lang = ["Ruby", "Java", "Python"]
lang.each {|s|
puts s
}

(1..3).each{|num|
puts "num = #{num}"
}

("A6"..."A9").each{|x|
puts x
}


<実行結果>

C:\ruby>ruby each.rb
Ruby
Java
Python
num = 1
num = 2
num = 3
A6
A7
A8


同様にオブジェクトから要素を取り出しながら処理をする方法としてfor文があります。構文は次の通りです。

for 変数 in オブジェクト do
#処理
end


<for.rb>

lang = ["Ruby", "Java", "Python"]

for s in lang do
puts s
end

for i in 1..3 do
puts i
end


<実行結果>

C:\ruby>ruby for.rb
Ruby
Java
Python
1
2
3

 

(3)条件が成立する間(しない間)繰り返し

条件式を評価した結果が真の間繰り返し処理を実行する方法として、while文があります。逆に、偽の間繰り返す方法として、until文があります。構文は次の通りです(doは省略可能)。

while 条件式 do
#処理
end

until 条件式 do
#処理
end


<while.rb>

num = 1

while num < 5 do
puts "num = #{num}"
num = num + 1
end

until num < 3 do
puts "num = #{num}"
num = num - 1
end

 

<実行結果>

C:\ruby>ruby while.rb
num = 1
num = 2
num = 3
num = 4
num = 5
num = 4
num = 3


また無限ループを実行するメソッドとしてloopがあります。ループ(繰り返し)から抜けるにはbreakを用います。


<loop.rb>

num = 0

loop {
num += 1
break if num == 4
puts "num = #{num}"
}


<実行結果>

C:\ruby>ruby loop.rb
num = 1
num = 2
num = 3

 

(4)繰り返しの制御

繰り返しの制御方法として、上で紹介したbreak(繰り返しを中断して抜ける)の他に、nextredoがあります。これらは共に繰り返しを再実行するメソッドですが、nextは次の繰り返しに進み、redoは同じ繰り返しをする点が異なります。


<next_redo.rb>

loop_num = 0

for for_cnt in 1..5 do
loop_num += 1
puts "(1) loop_num: #{loop_num}, for_count:#{for_cnt}"
next if loop_num == 2
redo if loop_num == 4
puts "(2) loop_num: #{loop_num}, for_count:#{for_cnt}"
end


<実行結果>

C:\ruby>ruby next_redo.rb
(1) loop_num: 1, for_count:1
(2) loop_num: 1, for_count:1
(1) loop_num: 2, for_count:2
(1) loop_num: 3, for_count:3
(2) loop_num: 3, for_count:3
(1) loop_num: 4, for_count:4
(1) loop_num: 5, for_count:4
(2) loop_num: 5, for_count:4
(1) loop_num: 6, for_count:5
(2) loop_num: 6, for_count:5



例外処理

Rubyでの例外処理は以下のように記述します。

begin
#例外が発生するかもしれない処理
rescue 例外クラス => 例外オブジェクトを格納する変数 then
#例外が発生したときの処理
else
#例外が発生しなかったときの処理
ensure
#例外の有無に関わらず最後に実行される処理
end


例外クラスや例外オブジェクトを格納する変数、thenelse節、ensure節等は省略可能です。
例外が発生したときは、例外オブジェクトに例外情報が格納されます。例外オブジェクトのメソッドclass, message, backtraceを使って例外情報を取得します。classでは「例外クラス」、messageでは「例外メッセージ」、backtraceでは「例外が発生した位置の情報」を取得できます。


<exception.rb>

begin
puts "a" + 4 #文字列と数値の足し算のため例外発生
rescue => ex
print "Class: ", ex.class, "\n"
print "Massage: ", ex.message, "\n"
puts "Backtrace:"
ex.backtrace.each{|trace| puts trace}
ensure
puts "Finish"
end


<実行結果>

C:\ruby>ruby exception.rb
Class: TypeError
Massage: can't convert Fixnum into String
Backtrace:
exception.rb:2:in `+'
exception.rb:2:in `<main>'
Finish


またraise関数によって明示的にエラーを発生させることもできます。下の例ではraiseで例外メッセージを指定していますが、例外クラスや例外オブジェクトを指定することもできます。


<raise.rb>

begin
raise "Exception!"
rescue => ex
print "Massage: ", ex.message, "\n"
puts "Backtrace:"
ex.backtrace.each{|trace| puts trace}
end


<実行結果>

C:\ruby>ruby raise.rb
Massage: Exception!
Backtrace:
raise.rb:2:in `<main>'


次は、標準入出力やファイル入出力について説明します。