Ruby 2.4

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

测试ifelsif可能有副作用。副作用最常见的用途是将值缓存到局部变量中:

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 不是假值。

您可以使用一个可选的thenunless一样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条件打印出“值为真” 。

您不得使用elsifunless表达。

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在体内被记录为不存在的方法,所以引发了 NameError。

同样如此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则执行。

elsethen是可选的,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'”。

你可以thenwhen条件后使用。这是最经常用来放置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

再次,thenelse是可选的。

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。

喜欢whileuntil,这do是可选的。

for循环类似于使用每一个,但不创建一个新的变量范围。

除非break使用for循环的结果值是迭代的值。

for循环在现代 Ruby 程序很少使用。

修饰符while和until

ifunlesswhile并且until可以用作改性剂:

a = 0 a += 1 while a < 10 p a # prints 10

until 用作修饰词:

a = 0 a += 1 until a > 10 p a # prints 11

您可以使用beginend创建一个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。这不再是真实的,现在当您retryrescue块外部使用时,您将收到 SyntaxError 。请参阅例外以正确使用retry

Flip-Flop

触发器是一个罕见的条件表达式。它的主要用途是用于从使用 ruby 一个行程序处理的文本ruby -nruby -p

触发器的形式是表示何时触发器打开的表达式,..(或...)表示何时触发器将关闭的表达式。当触发器处于打开状态时,它将继续评估truefalse关闭。

这里是一个例子:

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。

触发器必须条件这样的里面被用作ifwhileunlessuntil等,包括改性剂的形式。

当您使用包含范围(..)时,关闭条件在条件更改时进行评估:

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永远不会再是两次。