
Ruby 循环完全指南掌握loop、while、until、for、#times与#upto/#downto【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum本指南基于 cu/curriculumThe Odin Project 开源 Web 开发课程的 Ruby 基础课程 ruby/basic_ruby/loops.md 编写系统讲解 Ruby 中六类最常用的循环结构与 Range 区间语法。通过本文你将理解每种循环的适用场景、如何用条件控制循环退出、如何避免否定逻辑带来的可读性灾难并掌握从重复写代码走向 DRYDont Repeat Yourself编程的第一步为后续学习数组、哈希与 Enumerable 枚举方法打好基础。什么是循环为什么需要它循环Loop是反复执行直到某个条件满足的代码块。在编程中重复劳动是 Bug 的温床——手写十遍相同的输出你很可能在其中一遍打错一个字母。循环的意义在于代码写得越少引入 Bug 的机会就越少。正如本仓库在 ruby/basic_ruby/methods.md 中强调的DRYDont Repeat Yourself原则循环正是避免重复的第一种工具。本课所有示例都建议你在irb或任何在线 REPL 环境中边读边敲亲手感受每种循环的行为差异。本课的学习目标来自原文档 Lesson overview解释什么是循环以及它的用处解释什么是loop循环以及如何使用解释什么是while循环以及如何使用解释什么是for循环以及如何使用解释什么是#times循环以及如何使用解释什么是until循环以及如何使用解释什么是#upto和#downto循环以及如何使用loop永不放弃的无限循环loop是 Ruby 中最顽固的循环——它是一个无限循环除非你用break命令显式要求它停止否则它会一直运行下去。最常见的用法是让break带上一个条件i 0 loop do puts i is #{i} i 1 break if i 10 end上面的代码会依次输出i is 0到i is 9当i增长到 10 时触发break循环结束。需要指出的是在 Ruby 实际开发中loop并不常见。如果你发现自己正在使用loop很可能存在更合适的循环结构比如下面介绍的while或#times。loop更适合那些退出条件无法提前确定、需要先执行一次再判断的场景但在 Ruby 中这样的需求通常有其他更地道的写法。注loop配合do...end的写法本质上是在给Kernel#loop方法传递一个代码块。关于单行块{}与多行块do...end的约定可以参阅仓库中的 ruby/advanced_ruby/blocks.md。while循环条件前置意图一目了然while循环与loop类似区别在于你预先声明退出循环的条件i 0 while i 10 do puts i is #{i} i 1 end由于退出条件在循环开始前就已写明这段代码的意图比上面的loop版本清晰得多只要i 10为真就继续执行。while循环的另一个经典场景是反复向用户提问直到得到期望的答案while gets.chomp ! yes do puts Are we there yet? end这个例子展示了while的灵活性优势它会一直运行直到退出条件满足而运行次数可能是 1 次、4 次也可能是一开始根本无法预知的 79 次——一切取决于用户的输入。这里gets.chomp读取用户输入并去除末尾换行! yes判断输入是否不等于期望值循环在用户输入 yes 之前会一遍遍地追问。小贴士while条件中的do关键字在单行写法中可省略多行写法中写上do会让代码更易读。until循环while的反面拒绝否定逻辑until循环是while循环的对立面while条件为真时继续循环until条件为假时继续循环直到条件变为真才停止。这两种循环基本可以互换使用最终用哪个取决于你的退出条件怎么写更易读。原文档给出的指导原则是尽量避免用!逻辑非否定表达式。原因有二第一感叹号在代码中很难被注意到第二否定会让逻辑推理变得困难降低代码可读性——这正是until的用武之地。把上面的while例子改写成untili 0 until i 10 do puts i is #{i} i 1 end可以看到使用until意味着循环会一直运行直到条件i 10变为真。再来看看如何用until消除while版本中的!否定until gets.chomp yes do puts Do you like Pizza? end对比上面的while gets.chomp ! yesuntil gets.chomp yes读起来自然得多——一直问直到你回答 yes。关于真值判断Ruby 中只有nil和false会被当作假值其余一切包括0和空字符串都是真值。这在编写循环条件时至关重要详见 ruby/basic_ruby/conditional_logic.md。Range 区间定义循环的边界如果我们确切知道循环要执行多少次Ruby 允许使用 Range区间来定义一个间隔。只需给出起始值、结束值并指定区间是包含inclusive还是排除exclusive结束值(1..5) # inclusive range: 1, 2, 3, 4, 5 (1...5) # exclusive range: 1, 2, 3, 4 # We can make ranges of letters, too! (a..d) # a, b, c, d两个关键点..两个点是包含区间包含结束值...三个点是排除区间不包含结束值Range 不仅可以由数字构成字符串如字母a..d也可以。Range 是后面for循环、#upto/#downto以及 Enumerable 方法如#each频繁使用的基础类型。在原文档中Range 是学习for循环前的必备铺垫——因为它定义了要迭代多少次的边界。for循环遍历集合与区间for循环用于遍历一个集合如数组或 Range。当你需要执行固定次数、并且同时需要一个迭代器变量时它会非常方便for i in 0..5 puts #{i} zombies incoming! end这段代码会输出0 zombies incoming! 1 zombies incoming! 2 zombies incoming! 3 zombies incoming! 4 zombies incoming! 5 zombies incoming!for循环也可以遍历数组。仓库中 ruby/basic_ruby/basic_enumerable_methods.md 给出了一个筛选派对邀请名单的例子friends [Sharon, Leo, Leila, Brian, Arun] invited_list [] for friend in friends do if friend ! Brian invited_list.push(friend) end end invited_list # [Sharon, Leo, Leila, Arun]不过同样的课程紧接着就指出这种用for手写筛选的写法可以被 Enumerable 的#select/#reject一行替代因此在真实 Ruby 代码中for循环并不主流——这正是该课程在后续讲解枚举方法的原因。另外原文档附带的经验之谈是在 IRB 中写for循环时do关键字是可选的不加do有时能避免 IRB 的解析问题。for循环本质上是对集合调用#each的语法糖包装但它不会像#each那样产生块级作用域。理解两者差异后你会更倾向使用#each与块。#times循环指定次数的信任之选如果你需要精确运行指定次数的循环#times是最直接的选择。它会迭代指定次数还附带一个福利可以通过块参数访问当前迭代到的数字。5.times do puts Hello, world! end上面这段代码会输出 5 次Hello, world!——Ruby 的可读性就是这么直观。如果想在循环体中使用当前的迭代序号只需给块加上参数5.times do |number| puts Alternative fact number #{number} end注意循环默认从 0 开始计数除非另有指定所以第一次迭代输出的是Alternative fact number 0最后一次是Alternative fact number 4。从源码层面看#times、#upto等其实都是 RubyInteger 类的内置实例方法。本仓库的 ruby/basic_ruby/methods.md 在讲解内置方法时专门以Integer#times、Integer#upto为例说明方法与函数在纯面向对象的 Ruby 中的关系以及文档中#号前缀的约定——它表示一个实例方法。#upto与#downto从 A 数到 B或从 B 数回 A#upto和#downto方法的行为与它们的名字完全一致分别从起始数字向上或向下迭代到另一个数字。5.upto(10) { |num| print #{num} } # 5 6 7 8 9 10 10.downto(5) { |num| print #{num} } # 10 9 8 7 6 5如果你需要按特定范围步进遍历一串数字甚至字母这两个方法就是你的选择。与for不同#upto/#downto是标准库提供的对象方法块参数会拿到当前值代码意图从 5 数到 10一目了然。它们也是后续学习 Enumerable、编写数值迭代逻辑时经常使用的基础方法。如何选择正确的循环一张决策速查表把本课学到的六类循环放在一起对比选择依据非常清晰循环结构退出方式适用场景迭代次数是否提前已知loop循环体内的break通用无限循环先执行后判断未知while前置条件为假时退出条件为真继续如反复询问用户未知until前置条件为真时退出与while互补避免!否定未知for ... in遍历完集合/Range 后退出遍历数组、区间需要迭代器已知集合长度#times执行完指定次数后退出精确执行 N 次附带当前序号已知#upto/#downto到达上/下限后退出从 A 数到 B 或从 B 数回 A已知核心原则原文档明确强调能用更具体的循环就别用loop——如果发现自己在写loop大概率存在更贴切的写法能用until就别写!否定——可读性优先条件前置while/until比循环体内break更清晰——因为退出条件写在开头读者一眼就能看到循环的边界。实战练习在仓库项目中运用循环本课的 Assignment作业环节鼓励你完成两件事复习循环与迭代器的相关知识本仓库对应章节即 ruby/basic_ruby/loops.md后续还有 ruby/basic_ruby/basic_enumerable_methods.md 的#each、#map、#select、#reduce等内容原文档建议跳过其中的递归小节因为递归会在课程后期单独讲解对应仓库中的 ruby/computer_science/recursive_methods.md用不同的循环方法改写上面的示例实现相同结果——例如用#times改写while计数循环、用until改写while提问循环、用#upto改写for i in 0..5。当你真正开始写 Ruby 项目时循环会出现在各种地方。仓库中的 ruby/basic_ruby_projects/project_bubble_sort.md冒泡排序和 ruby/basic_ruby_projects/project_caesar_cipher.md凯撒密码等项目作业都需要你自行设计循环逻辑来反复比较/遍历数据——这正是检验本课知识掌握程度的绝佳机会。知识检查以下问题用于回顾本课要点原文档 Knowledge check什么是循环为什么它有用什么是loop循环如何正确使用它并安全退出什么是while循环如何正确使用它什么是for循环如何正确使用它什么是#times循环如何正确使用它它从几开始计数什么是until循环如何正确使用它它与while有何关系什么是#upto和#downto循环如何正确使用它们Range 区间中..与...的区别是什么下一步从循环走向 Enumerable掌握本课的循环语法后你会进入 Ruby 学习中更重要的一环Enumerable 枚举方法。仓库课程在 ruby/basic_ruby/basic_enumerable_methods.md 的开篇就明确指出你在之前的课程中学习了循环以及数组和哈希而枚举方法#each、#map、#select、#reduce等正是把循环中常见的转换、查找、筛选模式封装成可复用方法让 DRY 原则在迭代场景下发扬光大。例如用friends.select { |friend| friend ! Brian }一行替代 8 行的for循环加条件判断——这既是本课循环知识的延伸也是 Ruby 优雅之处的起点。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考