本章我们会讲述:
- 程序中的循环是什么
- 写循环时需要注意什么
- 循环的种类及其写法
6.1 循环的基础
6.2循环的注意事项
- 循环的主体是什么
- 停止循环的条件是什么
6.3 实现循环的方法
Ruby中有两种实现循环的方法
- 使用循环语句
利用 Ruby 提供现有的循环语句,可以满足大部分循环处理的需求。 - 使用方法实现循环
将块传给方法,然后在块里面写上需要循环的处理。一般我们在为了某种特定目的而需要定制循环结构时,才使用方法来实现循环。 下面是我们接下来要介绍的六种循环语句或方法。- times方法
- while语句
- each方法
- for语句
- until语句
- loop方法
6.4 times 方法
如果只是单纯执行一定次数的处理,用 times 方法可以很轻松实现。 假设我们希望把“满地油菜花”这个字符串连续输出 7 次。
7.times do
puts "满地油菜花"
end
执行示例:
ruby times.rb
满地油菜花
满地油菜花
满地油菜花
满地油菜花
满地油菜花
满地油菜花
满地油菜花
使用 times 方法实现循环时,需要用到块 do ~ end。
循环次数.times do
希望循环的处理
end
块的do ~ end部分可以用 {~}代替,即
循环次数.times {
希望循环的处理
}
6.5 for 语句
for 语句同样是用于实现循环的。需要注意的是,与刚才介绍的 times 方法不同,for 并不是方法,而是 Ruby 提供的循环控制语句。
代码清单 6.4 for.rb
sum = 0
for i in 1..5
sum = sum + i
end
puts sum
执行示例:
ruby for.rb
15
for 语句的结构:
for 变量in开始时的数值..结束时的数值 do
希望处理的循环
end
可以省略do
6.6 普通的for语句
for 变量 in 对象 do
希望循环的处理
end
下面是使用数组对象的例子。
names = ["awk", "Perl", "Python", "Ruby"]
for name in names
puts name
end
6.7 while 语句
不管哪种类型的循环,while 语句都可以胜任,while 语句的结构如下:
while 条件 do
希望循环的处理
end
6.8 until语句
与 if 语句相对的有 unless 语句,同样地,与 while 语句相对的有 until 语句。until 语句的结构与 while 语句完全一样,只是条件判断刚好相反,不满 足条件时才执行循环处理。换句话说,while 语句是一直执行循环处理,直到条件不成立为止;until 语句是一直执行循环处理,直到条件成立为止。
until 条件 do
希望循环的处理
end
虽然可以使用 while 语句的否定形式代替 until 语句。但是,有时对一些比较复杂的条件表达式使用否定,反而会不直观,影响程序理解,在这种情况下, 我们应该考虑使用 until 语句。
6.9 each 方法
each 方法将对象集合里的对象逐个取出,这与 for 语句循环取出数组元素非常相似。实际上,我们可以非常简单地将使用 for 语句的程序(代码清单 6.5) 改写为使用 each 方法的程序(代码清单 6.11)。
代码清单 6.11 each_names.rb
names = ["awk", "Perl", "Python", "Ruby"]
names.each do |name|
puts name
end
each 方法的结构如下:
对象.each do |变量|
希望循环的处理
end
块的 do ~ end 部分可换成 { ~ }。
这与下面的程序的效果是几乎一样。
for 变量 in 对象
希望循环的处理
end
在 Ruby 内部,for 语句是用 each 方法来实现的。因此,可以使用 each 方法的对象,同样也可以指定为 for 语句的循环对象。 在介绍 for 语句时我们举过使用范围对象的例子(代码清单 6.4),我们试着用 each 方法改写一下。
代码清单 6.12 each.rb
sum = 0
(1..5).each do |i|
sum = sum + i
end
puts sum
像本例这样,我们可以轻松互相改写两种用法。那到底什么时候该用 for 语句,什么时候该用 each 方法呢,我们将在本章的最后讨论这个问题。
6.10 loop 方法
还有一种循环的方法,没有终止循环条件,只是不断执行循环处理。Ruby 中的 loop 就是这样的循环方法。
loop do
print "Ruby"
end
执行上面的程序后,整个屏幕会不停的输出文字 Ruby。为了避免这样的情况发生,在实际使用 loop 方法时,我们需要用到接下来将要介绍的 break,使程 序可以中途跳出循环。
6.11 循环控制
break 终止程序,跳出循环
next 跳到下一次循环
redo 在相同的条件下重复刚才的处理
另外,大家要注意 redo 的使用方法,稍不留神就会在同样的条件下,不断地重复处理,陷入死循环中。 break、next 和 redo 中,一般比较常用是 break 和 next。大家应该熟练掌握这两个命令的用法。即使是 Ruby 默认提供的库里面,实际上也很难找到 redo 的踪影,所以当我们在希望使用 redo 时,应该好好考虑是否真的有必要使用 redo。
6.12 总结
如果纯粹只考虑实现循环功能,任何种类的循环都可以用 while 语句实现。讲得极端一点,其他循环语句和方法根本也没存在的必要。即便如此,那为什么 Ruby 还提供了那么丰富的循环语句和方法呢。这是因为,程序并不只是单纯为了实现功能,同时还应该使代码更便于读写,使人更容易理解。
下面我们简要介绍一下各种循环应在何时使用:
times 方法 确定循环次数时使用
for 语句 从对象去除元素时使用(each的语法糖)
while 语句 希望自由指定循环条件时使用
until 语句 使用while语句使循环变得难懂时使用
each 方法 从对象取出元素时使用
loop 方法 不限制循环次数时使用
PS:语法糖(syntax sugar),是指一种为了照顾一般人习惯而产生的特殊语法 1。例如,使用常规的语法调 用方法,那么加法运算应该写成 3.add(2)。 但是对于一般人来说,写成 3 + 2 会更直观,更简明易懂。 语法糖并不会加强编程语言的任何功能,但是对于提高程序的易读性来讲是不可或缺的。
确定循环次数时循环处理使用 times 方法,除此以外的大部分循环处理,根据情况选择 while 语句或者 each 方法,一般也能写出直观易懂的程序。请大家 先熟练掌握这三种循环方法。
do~end 与 {~}
在 times 方法的示例中,我们介绍了块的两种写法,do ~ end 与 { ~ }。从执行效果来看,两种方法虽然没有太大区别,但一般我们会遵守以下这 个约定俗成的编码规则:
- 程序是跨行写的时候使用 do ~ end。
- 程序写在 1 行的时候用 { ~ }。
例如:
10.times do |i|
puts i
end
or
10.times{|i| puts i
刚开始大家可能会有点不习惯。我们可以这样理解,do ~ end 表示程序要执行内容是多个处理的集合,而 { ~ } 则表示程序需要执行的处理只有一 个,即把整个带块的方法看作一个值。
如果用把 do ~ end 代码合并在一起,程序会变成下面这样:
10.times do |i| puts i end
以上写法,怎么看都给人一种很难断句的感觉。虽然实际上使用哪种写法都不会影响程序的运行,但在刚开始编写程序时,还是建议大家先遵守这个编 码规则。