## 5.循环
有时你可能需要执行一些重复性的任务,比如说我想编写一个火箭倒计时程序,我想创建一个自动为火箭倒数的机器人,当计数结束时会说“ Blast Off”,让我们写一个 看看
```rb
# count_down.rb
# Zigor tells about itself
puts "Hello, I am Zigor...."
puts "I count down for rockets"
# Count down starts
puts 10
p 9 # p is a short form for puts
p 8
p 7
p 6
p 5
p 4
p 3
p 2
p 1
p "Blast Off!"
```
好吧,希望你能理解上面的程序。 我想说明的是,`p`是`puts`的一种简短形式,不用写`puts`就能使用`p`并得到相同的结果 <sup class="footnote">[ [16 [](#_footnotedef_16 "View footnote.") ]</sup> 。 上面的程序在运行时显示以下内容
```rb
Hello, I am Zigor....
I count down for rockets
10
9
8
7
6
5
4
3
2
1
"Blast Off!"
```
如此完美的执行,但是我们可以提高代码的效率,我们很快就会看到
### 5.1。 向下
在你的文本编辑器中,键入以下程序
```rb
# count_down_1.rb
# Zigor tells about itself
puts "Hello, I am Zigor...."
puts "I count down for rockets"
# Count down starts
10.downto 1 do |num|
p num
end
p "Blast Off!"
```
运行它,看看。 好了,你的程序现在使用了更少的代码,但是却产生了相同的结果!
注意事情`10.downto 1`,该语句使 Zigor 从 10 倒数到 1,而在倒数的同时,你可以使用倒数值做一些事情,还可以在循环块中放入一些代码。 循环以`do`开始,并在遇到`end`命令时结束。 你输入的任何代码都应介于`do`和`block` <sup class="footnote">[ [17](#_footnotedef_17 "View footnote.") ]</sup> 之间
```rb
10.downto 1 do
# do some thing! Anything!!
end
```
因此,可以在`do`和`end`(技术上称为块)之间放置代码以打印倒数。 首先如何获得号码? 我们将在名为`num`的变量中获取它,因此我们将代码重写为如下所示
```rb
10.downto 1 do |num|
# put the printing stuff here
end
```
上面请注意,`num`被`|`和`|`包围。 现在我们需要做的就是打印它,所以我们只打印如下图所示
```rb
10.downto 1 do |num|
p num
end
```
### 5.2。 次
times 是一个非常简单的循环,如果你想让代码执行 N 次,则将代码放入其中。 现在让我们看看 Zigor 知道什么
```rb
# times.rb
puts "Hi, I am Zigor"
puts "I am going to tell what I know"
7.times{
puts "I know something"
}
```
好了,执行后程序会打印以下内容
```rb
Hi, I am Zigor
I am going to tell what I know
I know something
I know something
I know something
I know something
I know something
I know something
I know something
```
Zigor 告诉它它知道七次。
好的,我们已经在程序中进行了更改,这次我们将打印 count 变量,在下面键入程序并执行
```rb
# times_1.rb
puts "Hi, I am Zigor"
puts "I am going to tell what I know"
7.times{ |a|
puts "#{a}. I know something"
}
```
这就是你得到的结果
```rb
Hi, I am Zigor
I am going to tell what I know
0\. I know something
1\. I know something
2\. I know something
3\. I know something
4\. I know something
5\. I know something
6\. I know something
```
为什么从零数到六而不是一七呢? 好吧,如果一切按你的意愿进行,那么就不需要像你和我这样的程序员了,所以不要打扰。 请注意,在这些程序中,我们使用`{`和`}`,而不是 do and end。 好吧,Ruby 鼓励使用不同的编程风格。
### 5.3。 取决于
`upto`将从某个数字数到另一个数字。 就像倒过来一样。 输入以下程序并执行
```rb
# upto.rb
# upto is downto in reverse
17.upto 23 do |i|
print "#{i}, "
end
```
这是输出的样子
```rb
17, 18, 19, 20, 21, 22, 23,
```
### 5.4。 步
可以将`step`循环视为`upto`和`downto`的组合,将它们打包在一起,执行以下代码
```rb
# step_1.rb
# explains step function
1.step 10 do |i|
print "#{i}, "
end
```
这就是结果。 这与`upto`非常相似! 你没看到!!
```rb
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
```
现在,如下所示修改程序并将其保存为其他名称
```rb
# step_2.rb
# explains step function
10.step 1 do |i|
print "#{i}, "
end
```
执行该程序时不产生任何输出。 我们做错了什么? 如下所示修改程序并运行
```rb
# step_3.rb
# explains step function
# this time its stepping down
10.step 1, -1 do |i|
print "#{i}, "
end
```
好了,这是程序的输出
```rb
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
```
接下来会发生什么? 步骤接收三个输入,请考虑以下代码
```rb
10.step 1, -1
```
第一个是将调用步骤的号码作为初始号码,在上述情况下为`10`。 在这种情况下,下一个是结束号,即`1`,即此函数从 10 到 1 计数,在这种情况下,我们必须递减,因此计数必须以`-1`为步长。
我可以修改同一程序,以 10 到 1 的方式打印偶数,如下所示
```rb
# step_4.rb
# explains step function
# this time its stepping down
p "Even numbers between 10 and 1:"
10.step 1, -2 do |i|
print "#{i}, "
end
```
该程序输出以下输出
```rb
“Even numbers between 10 and 1:”
10, 8, 6, 4, 2,
```
现在让我们尝试一个程序,该程序将按升序打印从 1 到 10 的偶数
```rb
# step_4.rb
# explains step function
# this time its stepping upby two counts each loop
p "Even numbers between 1 and 10:"
2.step 10, 2 do |i|
print "#{i}, "
end
```
输出量
```rb
“Even numbers between 1 and 10:”
2, 4, 6, 8, 10,
```
在上面的代码中,从 2 开始,我们将在 10 结束,然后以 2 的步长跳过每个循环。在循环内部,我们仅打印在变量`i`中捕获的迭代值。
### 5.5。 而
尽管 <sup class="footnote">[ [18](#_footnotedef_18 "View footnote.") ]</sup> 循环是一个循环,直到满足条件为止。 阅读下面的代码
```rb
# while.rb
i=1
while i<=10 do
print "#{i}, "
i+=1
end
```
执行后,将产生以下输出。
```rb
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
```
现在让我们看看 while 循环是如何工作的。 While 循环通常包含四个重要部分
1. 初始化
2. 条件检查
3. 圈体
4. 更新中
**初始化**
参见语句`i=1`,在这里我们初始化名为`i`的变量并将其设置为`1`值。
**条件检查**
参见语句`while i⇐10`,在该语句中,我们指定我们开始一个 while 循环,每次迭代时,该 while 循环都会检查`i`的值,如果其小于或等于`10`,则循环主体会盲目地 被执行。
**环体**
注意程序中的`do`和`end`,`do`代表循环代码块的开始,`end`代表循环代码块的结束。 在它们之间,我们有一些陈述,我们将很快讨论。 声明之一是打印`i`的值,该值由`print "#{i}, "`完成
**更新**
假设我们忘了在循环体中包含`i+=1`,在每次迭代结束时,`i`的值将始终保持为 1,而我将始终保持小于 10,因此循环将被执行无数次,并且 将打印无限的 1。 实际上,你的程序将崩溃,并可能导致不良后果。 为了避免这种情况,我们必须包含更新声明。 在这里,我们放置了`i+=1`,它在每次迭代继续时将`i`的值增加一,这确保`i⇐10`在某个阶段变为`false`,因此循环停止执行 <sup class="footnote">[ [19 [](#_footnotedef_19 "View footnote.") ]</sup> 。
因此,我们看到,为了使循环以理想的方式工作,我们需要使这四个部分交响。
### 5.6。 直到
`while`循环持续进行直到条件变为`false`,直到循环持续进行直到条件变为`true`。 阅读下面的代码,在文本编辑器中键入并执行它。
```rb
# until.rb
i=1
until i>10 do
print "#{i}, "
i+=1
end
```
这就是你将得到的结果
```rb
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
```
那么这个循环如何工作? 首先,我们设置`i=1`,然后使用直到命令`i`大于 10 之前,请在此行`until i>10 do`中继续执行操作。 在`do`和`end`关键字之间说了些什么。 因此,直到条件失败,循环主体中的代码将被执行,因此我们将输出 1 到 10。
### 5.7。 打破
假设你想脱离循环,也就是停止执行循环,可以使用`break`命令。 下面给出一个例子。 在示例中,如果迭代变量`i`变为 6,我们将中断操作。因此,仅输出 1 到 5 范围内的数字。 当`i`变为 6 时,循环中断或终止
```rb
#break.rb
1.upto 10 do |i|
break if i == 6
print "#{i}, "
end
```
执行后,上面的程序产生以下输出
```rb
1, 2, 3, 4, 5,
```
### 5.8。 下一个
`break`,退出循环并终止。 `next`与`break`有所不同,它不是中断循环,而是继续循环而不执行`next`之后发生的语句的信号。 这是一个供你理解的示例
```rb
# next.rb
# This loop won't print 6
10.times do |num|
next if num == 6
puts num
end
```
Output
```rb
0
1
2
3
4
5
7
8
9
```
如果你注意到输出,则看到打印了从 0 到 9 的数字,但没有打印出 6。请注意 [next.rb](code/next.rb) 中的`next if num == 6`行,如果`num`为`6`,`next`被执行,换言之`do` `end`块之后的所有行均被跳过。 与`brake`不同,循环不会终止,而是仅跳过`next`之后的行,循环继续进行。
### 5.9。 重做
还有另一件事`redo`。 `next`进一步跳过任何执行,并且迭代变量递增/递减到下一个可能的值 <sup class="footnote">[ [20](#_footnotedef_20 "View footnote.") ]</sup> ,另一方面,`redo`跳过循环块中代码的进一步执行 ,但迭代变量不会增加,而是重新运行循环。 输入以下代码并执行
```rb
# redo.rb
5.times do |num|
puts "num = #{num}"
puts "Do you want to redo? (y/n): "
option = gets.chop
redo if option == 'y'
end
```
运行它,希望你可以自己解释;-)
### 5.10。 环
因此,到目前为止,我们已经看到了许多类型的循环,但是我省略了一个称为`loop`的基本循环。 为什么我忽略了它,因为使用 <sup class="footnote">[ [21](#_footnotedef_21 "View footnote.") ]</sup> 危险。 好吧,让我们看一个例子。 在下面键入程序并执行。 请注意,你需要按 Ctrl + C 才能停止执行。 所以要小心一点
```rb
# loop.rb
loop do
puts "I Love Ruby"
end
```
```rb
Output
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
I Love Ruby
......
```
输出将继续打印`I Love Ruby`,直到你按 Ctrl 和 C 键使输出断开为止。 基本是这样的:循环执行和结束之间的任何操作都将继续进行。
现在让我们说我们不希望这个循环永远持续运行。 让我们看看如何驯服它。 让我们打印一个可以打印 1 到 10 的程序。在下面键入该程序并运行。
```rb
# break_at_10.rb
i = 1
loop do
puts i
break if i == 10
i = i+1
end
```
Output
```rb
1
2
3
4
5
6
7
8
9
10
```
因此,程序可以按我们希望的那样打印 1 到 10。 让我们来看看它如何工作。 第一行`i = 1`将值`1`存储在名为`i`的变量中。 接下来,我们有这条`loop do`行,在这行和`end`之间放置的任何东西都将连续运行。
在下一行`puts i`中,我们打印`i`的值,因此打印了`1`,现在在`break if i == 10`中,它检查`i`是否为 10,此处的条件是`false`为`i` 不是 10,因此循环将继续到下一个语句`i = i + 1`,我们将`i + 1`中的`i`加 1,因此它变成 2,因此通过说`i = i + 1`表示`i = 1 + 1`,因此`i`将 变为 2 并且它(程序)符合`end`语句,这并不意味着 end,它仅意味着循环结束的迭代,因此再次返回顶部(即`loop do`)。
因此,在循环执行中,现在`i`为 2,因此事情不断进行,直到`i`为`10`,在这种情况下,在`break if i == 10`中,`i == 10`变为`true`并中断了循环。
**练习**:尝试修改 [break_at_10.rb](code/break_at_10.rb) ,当我们完成打印 10 时,程序必须打印“妈妈我已经完成打印 10”。
**答案:** [telling_mom.rb](code/telling_mom.rb)
**练习:**这些西方人不喜欢 13,所以编写了一个程序以从 1 10 20 开始打印,但是省略了 13。答案: [no_13.rb](code/no_13.rb)
**练习:**请说明 [no_13_a.rb](code/no_13_a.rb) 是否有效。 如果是,怎么办? 如果否,为什么不呢? <sup class="footnote">[ [22](#_footnotedef_22 "View footnote.") ]</sup>
- 前言
- 红宝石
- 先决条件
- 1.安装 Ruby
- 2.在线资源
- 3.入门
- 4.比较与逻辑
- 5.循环
- 6.数组
- 7.哈希和符号
- 8.范围
- 9.功能
- 10.可变范围
- 11.类&对象
- 12.安全导航
- 13.打破大型程序
- 14.结构和 OpenStruct
- 15. Rdoc
- 16. Ruby 样式指南
- 17.模块和混入
- 18.日期和时间
- 19.文件
- 20. Proc,Lambda 和块
- 21.多线程
- 22.异常处理
- 23.正则表达式
- 24.宝石
- 25.元编程
- 26.基准
- 27.测试驱动开发
- 28.观察者模式
- 29.模板模式
- 30.工厂模式
- 31.装饰图案
- 32.适配器模式
- 33.单例模式
- 34.复合模式
- 35.建造者模式
- 36.策略模式
- 赞助商
- 捐
- 人们怎么说
- 版权
- 取得这本书