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 区块。