ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 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`并得到相同的结果 &lt;sup class="footnote"&gt;[ [16 [](#_footnotedef_16 "View footnote.") ]&lt;/sup&gt; 。 上面的程序在运行时显示以下内容 ```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` &lt;sup class="footnote"&gt;[ [17](#_footnotedef_17 "View footnote.") ]&lt;/sup&gt; 之间 ```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。 而 尽管 &lt;sup class="footnote"&gt;[ [18](#_footnotedef_18 "View footnote.") ]&lt;/sup&gt; 循环是一个循环,直到满足条件为止。 阅读下面的代码 ```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`,因此循环停止执行 &lt;sup class="footnote"&gt;[ [19 [](#_footnotedef_19 "View footnote.") ]&lt;/sup&gt; 。 因此,我们看到,为了使循环以理想的方式工作,我们需要使这四个部分交响。 ### 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&gt;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`进一步跳过任何执行,并且迭代变量递增/递减到下一个可能的值 &lt;sup class="footnote"&gt;[ [20](#_footnotedef_20 "View footnote.") ]&lt;/sup&gt; ,另一方面,`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`的基本循环。 为什么我忽略了它,因为使用 &lt;sup class="footnote"&gt;[ [21](#_footnotedef_21 "View footnote.") ]&lt;/sup&gt; 危险。 好吧,让我们看一个例子。 在下面键入程序并执行。 请注意,你需要按 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) 是否有效。 如果是,怎么办? 如果否,为什么不呢? &lt;sup class="footnote"&gt;[ [22](#_footnotedef_22 "View footnote.") ]&lt;/sup&gt;