Control Expressions
控制表达式
Ruby 有多种方式来控制执行。这里描述的所有表达式都返回一个值。
对于这些控制表达式中的测试,nil
并且false
是假值true
和任何其他对象都是真值。在这个文件中,“真”意味着“真值”和“假”意味着“假值”。
if 表达
最简单的if
表达式有两个部分,一个是 “test” 表达式和一个 “then” 表达式。如果“测试”表达式评估为真,则评估“那么”表达式。
这是一个简单的 if 语句:
if true then
puts "the test resulted in a true-value"
end
这将打印出“测试结果为真实值”。
then
是可选的:
if true
puts "the test resulted in a true-value"
end
本文档将省略then
所有表达式的可选项,因为这是最常见的用法if
。
你也可以添加一个else
表达式。如果测试未评估为真,则else
表达式将被执行:
if false
puts "the test resulted in a true-value"
else
puts "the test resulted in a false-value"
end
这将打印出“测试结果为假值”。
您可以使用添加任意数量的额外测试到 if 表达式elsif
。一个elsif
当上述所有测试执行elsif
都是假的。
a = 1
if a == 0
puts "a is zero"
elsif a == 1
puts "a is one"
else
puts "a is some other value"
end
这将打印“一个是” 1
不等于0
。由于else
仅在没有匹配条件时执行。
一旦条件匹配,if
条件或任何elsif
条件,if
表达式就完成了,不再执行进一步的测试。
像一个if
,一个elsif
条件可能会跟着一个then
。
在这个例子中只有“a is one”被打印出来:
a = 1
if a == 0
puts "a is zero"
elsif a == 1
puts "a is one"
elsif a >= 1
puts "a is greater than or equal to one"
else
puts "a is some other value"
end
测试if
和elsif
可能有副作用。副作用最常见的用途是将值缓存到局部变量中:
if a = object.some_value
# do something to a
end
if
表达式的结果值是表达式中执行的最后一个值。
Ternary if
你也可以使用?
和写一个 if-then-else 表达式:
。这三元如果:
input_type = gets =~ /hello/i ? "greeting" : "other"
与此if
表达式相同:
input_type =
if gets =~ /hello/i
"greeting"
else
"other"
end
虽然三元 if 比写得比较冗长的形式要短得多,但为了便于阅读,建议三元if仅用于简单条件。此外,避免在同一表达式中使用多个三元条件,因为这可能会造成混淆。
unless 表达
unless
表达式是相反if
的表达。如果该值为 false,则执行 “then” 表达式:
unless true
puts "the value is a false-value"
end
这不会打印任何内容,因为 true 不是假值。
您可以使用一个可选的then
带unless
一样if
。
请注意,上述unless
表达式与以下内容相同:
if not true
puts "the value is a false-value"
end
就像if
表达式一样,您可以使用以下else
条件unless
:
unless true
puts "the value is false"
else
puts "the value is true"
end
这从else
条件打印出“值为真” 。
您不得使用elsif
与unless
表达。
unless
表达式的结果值是表达式中执行的最后一个值。
修饰符if和unless
if
并且unless
也可以被用于修改的表达式。当用作修饰符时,左边是 “then” 表达式,右边是 “test” 表达式:
a = 0
a += 1 if a.zero?
p a
这将打印1。
a = 0
a += 1 unless a.zero?
p a
这将打印0。
虽然修饰符和标准版本同时具有“测试”表达式和“然后”表达式,但由于解析顺序,它们并不是彼此的精确转换。以下是一个显示不同之处的例子:
p a if a = 0.zero?
这引发了 NameError“ 未定义的局部变量或方法`a'”。
当 ruby 分析这个表达式时,它首先会a
在 “then” 表达式中遇到一个方法调用,然后它会a
在 “test” 表达式中看到该赋值并将其标记a
为局部变量。
当运行这条线时,它首先执行“测试”表达式a = 0.zero?
。
由于测试是真的,它执行“then”表达式,p a
。由于a
在体内被记录为不存在的方法,所以引发了 Na
meError。
同样如此unless
。
case 表达
case
表达式可以以两种方式使用。
最常见的方法是将对象与多种模式进行比较。这些模式使用+ === +方法进行匹配,该方法在 Object 上使用别名+ == +。其他类必须覆盖它以提供有意义的行为。有关示例,请参阅模块#===和正则表达式#===。
下面是一个case
用来比较 String 和模式的例子:
case "12345"
when /^1/
puts "the string starts with one"
else
puts "I don't know what the string starts with"
end
这里通过调用返回值"12345"
来比较字符串。与表达式一样,匹配的第一个匹配被执行,所有其他匹配都被忽略。/^1//^1/ === "12345"trueifwhen
如果找不到匹配项,else
则执行。
else
和then
是可选的,case
表达产生相同的结果与上述一个:
case "12345"
when /^1/
puts "the string starts with one"
end
你可以在同一个地方放置多个条件when
:
case "2"
when /^1/, "2"
puts "the string starts with one or is '2'"
end
Ruby 会依次尝试每个条件,所以首先/^1/ === "2"
返回false
,然后"2" === "2"
返回true
,所以打印出“字符串以1开头或者是'2'”。
你可以then
在when
条件后使用。这是最经常用来放置when
在一条线上的主体。
case a
when 1, 2 then puts "a is one or two
when 3 then puts "a is three"
else puts "I don't know what a is"
end
使用case
表达式的另一种方式就像是一个 if-elsif 表达式:
a = 2
case
when a == 1, a == 2
puts "a is one or two"
when a == 3
puts "a is three"
else
puts "I don't know what a is"
end
再次,then
和else
是可选的。
case
表达式的结果值是表达式中执行的最后一个值。
while 循环
while
循环执行,而条件为真:
a = 0
while a < 10 do
p a
a += 1
end
p a
打印数字0到10. a < 10在进入循环之前检查条件,然后执行主体,然后再次检查条件。当条件结果为 false 时,循环终止。
do
关键字是可选的。以下循环等同于上面的循环:
while a < 10
p a
a += 1
end
while
循环的结果是nil
除非break
用于提供值。
until 循环
until
循环执行,而条件是假的:
a = 0
until a > 10 do
p a
a += 1
end
p a
这会打印数字0到11.与 while 循环一样a > 10,进入循环时每次执行循环体时都会检查条件。如果条件为假,循环将继续执行。
像while
循环一样,do
是可选的。
像while
循环一样,循环的结果until
是零,除非break
被使用。
for 循环
该for
循环由for
一个变量组成,后面跟着一个变量以包含迭代参数,后面跟着in
使用每个参数迭代的值。do
是可选的:
for value in [1, 2, 3] do
puts value
end
打印1,2和3。
喜欢while
和until
,这do
是可选的。
for
循环类似于使用每一个,但不创建一个新的变量范围。
除非break
使用for
循环的结果值是迭代的值。
for
循环在现代 Ruby 程序很少使用。
修饰符while和until
像if
和unless
,while
并且until
可以用作改性剂:
a = 0
a += 1 while a < 10
p a # prints 10
until
用作修饰词:
a = 0
a += 1 until a > 10
p a # prints 11
您可以使用begin
和end
创建一个while
循环,在条件之前运行一次该主体:
a = 0
begin
a += 1
end while a < 10
p a # prints 10
如果你不使用rescue
或者ensure
,Ruby 优化任何异常处理开销。
break Statement
使用break
可以尽早离开。values
如果其中一个是偶数,这将停止迭代项目:
values.each do |value|
break if value.even?
# ...
end
您也可以while
使用break
以下命令终止循环:
a = 0
while true do
p a
a += 1
break if a < 10
end
p a
这将打印数字0和1。
break
接受一个值,该值提供表达式结果“破坏”的结果:
result = [1, 2, 3].each do |value|
break value * 2 if value.even?
end
p result # prints 4
next Statement
使用next
跳过当前迭代的其余部分:
result = [1, 2, 3].map do |value|
next if value.even?
value * 2
end
p result # prints [2, nil, 6]
next
接受可用作当前块迭代结果的参数:
result = [1, 2, 3].map do |value|
next value if value.even?
value * 2
end
p result # prints [2, 2, 6]
redo Statement
使用redo
重做当前迭代:
result = []
while result.length < 10 do
result << result.length
redo if result.last.even?
result << result.length + 1
end
p result
这会打印 0,1,3,3,5,5,7,7,9,9,11
在Ruby 1.8中,你也可以使用retry
你使用的地方redo
。这不再是真实的,现在当您retry
在rescue
块外部使用时,您将收到 SyntaxError 。请参阅例外以正确使用retry
。
Flip-Flop
触发器是一个罕见的条件表达式。它的主要用途是用于从使用 ruby 一个行程序处理的文本ruby -n
或ruby -p
。
触发器的形式是表示何时触发器打开的表达式,..
(或...
)表示何时触发器将关闭的表达式。当触发器处于打开状态时,它将继续评估true
和false
关闭。
这里是一个例子:
selected = []
0.upto 10 do |value|
selected << value if value==2..value==8
end
p selected # prints [2, 3, 4, 5, 6, 7, 8]
在上面的例子中,开启条件是n==2
。触发器最初关闭(假)为0和1,但在2时开启(真),并保持在8上.8关闭后,关闭9和10。
触发器必须条件这样的里面被用作if
,while
,unless
,until
等,包括改性剂的形式。
当您使用包含范围(..
)时,关闭条件在条件更改时进行评估:
selected = []
0.upto 5 do |value|
selected << value if value==2..value==2
end
p selected # prints [2]
在这里,触发器的两端都被评估,所以触发器只有在value
等于2 时才会打开和关闭。由于触发器在迭代中打开,它将返回 true。
当您使用独占范围(...
)时,关闭条件将在以下迭代中进行评估:
selected = []
0.upto 5 do |value|
selected << value if value==2...value==2
end
p selected # prints [2, 3, 4, 5]
这里,触发器在value
等于2 时打开,但在同一次迭代中不关闭。关闭条件不会被评估,直到接下来的迭代,并且value
永远不会再是两次。