Ruby Programming/Syntax/Control Structures
條件分支(Conditional Branches)
編輯Ruby可藉由條件分支控制程式執行的流程。條件分支依據一個條件式的測試結果為真值或偽值,而將流程將轉移至相關連的程式區塊。若條件式計算結果為 false
或 nil
,則視為條件不符 (測試為偽);否則條件成立 (測試為真)。注意,數值 0
視同真值;其他語言多數將 0
視同其偽值。
在許多常見的程式語言中,條件分支是一種敘述,它們決定哪段程式區塊被執行但本身沒有值。 Ruby 則將條件分支作為式子,所以它們也有值。舉例而言,一個 if
式子不只決定執行哪段程式區塊,它本身也會有一個結果值。如下例,該 if
式子之計算結果值為 3:
if true 3 end
if
編輯語法:
if 條件式 then ...程式區塊... elsif 其他條件式 then ...程式區塊... elsif 其他條件式 then ...程式區塊... else ...程式區塊... end
範例:
a = 5 if a == 4 a = 7 end print a # prints 5 since the if-block isn't executed
通常我們省略保留字 then
。若想在一行內寫出完整的 if
式,則必須以 then
隔開條件式和程式區塊。如下所示:
if a == 4 then a = 7 end
程序員可藉由 elsif
與 else
區塊加上更多可用的測試條件以滿足其他需要考慮的情況。僅當執行 if
區塊之條件不符時,才會再考慮 elsif
與 else
區塊之執行條件。在一個完整的 if
式中,可以有任意數目的 elsif
區塊,但只能有一個 if
和一個 else
區塊。
if修飾片語
編輯上述範例亦可改用片語形式表達:
a = 5 a = 7 if a == 4
if
修飾片語表示當 if
右邊之條件成立時才執行 if
左邊的式子。此一由右到左的演算邏輯並不常見,但它提供了更貼近日常用語的表達形式。由於它不需要 end
結束敘述,所以也具有文字簡潔的優點。 if修飾片語慣例上用於敘述需要加上條件判斷且條件式可以簡短地在一行中寫完的情況。
unless
編輯unless
式和 if
式作用相反,僅當條件不符時才執行相關連的程式區塊。
範例:
a = 5 unless a == 4 a = 7 end print a # prints 7 since the if-block is executed
可將 unless
式看作 if
式之否定型:
if !expression # 此式等於下式 unless expression
unless修飾片語
編輯如同 if修飾片語,unless
也有修飾片語,如下:
a = 5 a = 7 unless a == 4 print a # prints 7 since the if-block is executed
short-if
編輯"short-if" 敘述讓我們以很簡短的方式計算式子並回傳一個值。這經常用於串接字串時。
範例:
a = 5 plus_or_minus = '+' print "The number+1 is: " + (plus_or_minus == '+' ? (a+1).to_s : (a-1).to_s) + "."
"short-if"之語法即 [條件式 ? 式1 : 式2] ,當條件式為真時傳回式1之值,否則傳回式2之值。它也被稱為三元運算子。由於其可讀性較差,建議只使用於次要的工作,如字串格式動作。
irb> true ? 't' : 'f' => "t" irb> false ? 't' : 'f' => "f"
case
編輯我們使用 case
敘述測試一連串的條件。其作用類似 C 和 Java 之中的 switch
,但使用方式更強大。
irb> i=8 => 8 irb> case i irb> when 1, 2..5 irb> puts "1..5" irb> when 6..10 irb> puts "6..10" irb> end 6..10 => nil
2..5
是表示 範圍(range) 的式子,此例指示在 2 到 5 以內的範圍。如下列算式便可測試 i
的值是否處於 2 到 5 以內之範圍:
(2..5) === i
case
內部使用運算子 ===
一次測試多個條件式。基於 Ruby 的個體導向本性,出現在 when
條件中的個體會套用 ===
運算,作用如同 (6..10) === i
。
在下例中,將會測試字串是否等於第一個 when
中的字串,接着測試是否符合第二個 when
的字樣規則式。
irb> case 'abcdef' irb> when 'aaa', 'bbb' irb> puts "aaa or bbb" irb> when /def/ irb> puts "includes /def/" irb> end includes /def/ => nil
迴圈(Loops)
編輯while
編輯一個 while
式就是一個反覆執行的 if
式。只要條件成立,程式區塊的內容就會一次又一次地執行。其語法為 while condition ... end
,其中包含當 condition 為真時就重複執行的程式區塊。
語法:
while 條件式 do ...程式區塊... end
while 條件式 : ...程式區塊... end
語法中之 do 或 : 可以省略不寫。但若要在一行內寫出 while 式,則必須以 do 或 : 隔開條件式或程式區塊。
範例:
i = 0 while i < 3 : puts i i += 1 end
while修飾片語
編輯while
也和 if
、unless
一樣,有可用於單獨敘述的修飾片語:
irb> i = 0 => 0 irb> puts i+=1 while i < 3 3 => nil
下列狀況也可以運作:
line = inf.readline while line != "what I'm looking for"
當迴圈第一次測試條件式時,區域變數 line
尚未定義,此時其值將被視為 nil
參與條件式測試。
until
編輯until
式是 while
的否定型,當條件式不符時才會反覆執行。
until修飾片語
編輯until
也可用修飾片語。
for
編輯Ruby 的 for
可提供與 C 的 for
相同的功用,但更有彈性。迴圈可以自行從一個聚合體(colection) - 如陣列、雜湊表、連續數值範圍等等 - 提取一個元素執行,而不需程序員指示它怎麼做:
語法:
for elt in colection do # 在此處, elt 參照聚合體中的一個元素。 ...程式區塊... end
for elt in colection : # 在此處, elt 參照聚合體中的一個元素。 ...程式區塊... end
與while相同, do 或 : 可省略。
聚合體也可以是一個數值範圍,這用法便是多數人所說的 for 迴圈用法:
irb> for num in (4..6) do irb> puts num irb> end 4 5 6 => 4..6
此例示範如何從頭到尾一一處理陣列元素:
for elt in [100, -9.6, "pickle"] puts "#{elt}\t(#{elt.class}) end 100 (Fixnum) -9.6 (Float) pickle (String) => [100, -9.6, "pickle"]
在 Ruby 中, for
其實就是 each
迭代器的另一種寫法。下列兩種句型之意義相等:
# C 程序員習慣這種: for element in collection : #... do something end
# Smalltalk 程序員習慣這種: collection.each {|element| #... do something }
迭代器通常可以取代傳統的迴圈,一般說來使用迭代器會方便得多。
break
編輯break
的意義是脫離迴圈。
next
編輯next
的意義是跳到迴圈起始處繼續下一個迭代 (如同 C 的 continue
)。
redo
編輯redo
將重新開始現行的迭代。
下列以 C 程式碼表現 Ruby 中的 break
, next,
和 redo
之作用:
while (condition) { label_redo: goto label_next; /* Ruby's "next" */ continue; goto label_break; /* Ruby's "break" */ break; goto label_redo; /* Ruby's "redo" */ label_next: } label_break:
return
編輯return
不只是脫離迴圈,也會脫離包含這迴圈的方法(method)。如果給它一個引數,該引數將視為方法的回傳值,而不是傳回 nil
。
於迭代器或程式區塊之中使用 return
時,其意義為脫離包含迭代器或程式區塊的方法,而非僅脫離迭代器或程式區塊。
@@a = [1, 2, 3] def q1 @@a.inject(0) {|sum, x| x+=1 return sum + x } end def q2 @@a.inject(0) {|sum, x| x+=1 sum + x } end
上例中,return
將直接脫離 q1 方法並回傳sum + x
之值,而非僅脫離 inject 區塊。