while、until、loop 與 for


while迴圈根據所指定的條件式來判斷是否執行迴圈本體,例如以下是個求最大公因數的程式:
# encoding: Big5
puts "輸入兩個數字..."
m = gets.to_i
n = gets.to_i
while n != 0
r = m % n
m = n
n = r
end
puts "GCD: #{m}"

while迴圈為前測式迴圈,因為它在迴圈執行前就會進行條件判斷,而begin...while為後測式迴圈,它會先執行迴圈本體,然後再進行條件判斷,例如:
# encoding: Big5
begin
print "輸入數字:"
printf "輸入數為 %s\n", gets.to_i % 2 == 0 ? "偶數" : "奇數"
print "繼續?(Yes/No)"
end while gets.chomp == "Yes"

while還有個行內用法,例如以下程式可取得隨機偶數:
n = 1
n = (rand() * 10).to_i while n % 2 == 1
print n

與while相反的是until,while是條件式成立時,執行迴圈本體,until是直到條件式成立前,都要執行迴圈本體。例如先前求最大公因數的程式,可以改為:
# encoding: Big5
puts "輸入兩個數字..."
m = gets.to_i
n = gets.to_i
until n == 0
r = m % n
m = n
n = r
end
puts "GCD: #{m}"

until也可以先執行迴圈本體,再測試條件式成立與否。例如:
# encoding: Big5
begin
print "輸入數字:"
printf "輸入數為 %s\n", gets.to_i % 2 == 0 ? "偶數" : "奇數"
print "繼續?(Yes/No)"
end until gets.chomp == "No"

until也可以用行內寫法。例如:
n = 1
n = (rand() * 10).to_i until n % 2 != 1
print n

如果想要無窮執行迴圈,可以使用loop方法。例如:
# encoding: Big5
loop { print "永不停止的 Orz..." }

loop是個方法,就像使用數值的times方法一樣,必須使用區塊指定執行內容;數值的times方法,也常用在指定次數的迴圈。例如:
# encoding: Big5
10.times do |i|
puts "第 #{i + 1} 次的 Orz..."
end

先前 陣列型態 談過,可以使用陣列的each方法逐一取得元素,也可以使用for逐一取得陣列元素:
# encoding: Big5
[1, 2, 3, 4, 5].each do |element|
print element
end
puts
for element in [1, 2, 3, 4, 5]
print element
end

事實上,只要物件上有each方法,就可以使用forfor其實是利用了each方法的語法,正確來說,each是迭代器(之後會說明迭代器的撰寫方式),先前談過的loop、times方法也是迭代器。

無論是while、until、for或是迭代器,都可以搭配break、next與redo來控制流程。例如:
# encoding: Big5
loop do
print "輸入數字:"
number = gets.to_i
printf "輸入數為 %s\n" % (number % 2 == 0 ? "偶數" : "奇數")
print "繼續?(Yes/No)"
if gets.chomp == "No"
break
end
end

break可用於中斷目前迴圈或迭代器的執行,next則會直接進行「下一次迴圈」,。例如:

# 底下顯示 1234
for i in 1..9
if i == 5
break
end
print i
end
puts
# 底下顯示 12346789
for i in 1..9
if i == 5
next
end
print i
end

第一段for程式會顯示1到4,因為當i 等於5時就會執行break而離開迴圈;第二段for程式會顯示1到4,然後是6到9,當 i 等於5時,會執行next直接進行下一次迴圈,這次迴圈print該行並沒有被執行,所以5並沒有被顯示。

redo是重作「一次redo前的區塊內容」(不是重作「一次迴圈」)。例如:
# 底下顯示 1234redoredoredo....
for i in 1..9
if i == 5
print "redo"
redo
end
print i
end

redo並沒有重作一次迴圈,而是重作一次redo前的區塊內容,因此上例i等於5時,並沒有進行for該行設定i的動作,而是重作一次for該行之後的區塊,所以i一直都會是5,然後符合if條件而不斷redo。