Ruby 控制流
控制流让程序能"做判断"和"重复干活"。本章讲 Ruby 的所有控制流结构——if、unless、case、while、until 以及各种迭代器。Ruby 的迭代器方法非常丰富,实际项目里几乎不用 for 循环,这是它和别的语言最大的区别之一。
1. if/elsif/else
最基础的条件分支:
# 基础 if/elsif/else
score = 85
if score >= 90
puts "优秀"
elsif score >= 80
puts "良好" # 这条会输出
elsif score >= 60
puts "及格"
else
puts "不及格"
end注意是 elsif(少一个 e),不是 elseif、不是 else if。这是 Ruby 借鉴 Perl 的写法,新手写错率很高。
2. 后置 if 修饰符(Ruby 特色)
Ruby 允许把 if/unless 写在语句后面,这让代码非常像英文:
# 后置 if 修饰符:简单条件一行搞定
puts "成年" if age >= 18
puts "免费" if user.vip?
# 后置 unless:条件为 false 时执行(等于 if !)
puts "未成年" unless age >= 18
raise "名字不能为空" unless name
# 三元运算符:也属于条件分支
status = age >= 18 ? "成年" : "未成年"实际项目里大量使用,典型场景:
raise "..." if 条件——参数检查。next if 条件——循环跳过。return if 空数据——早返回。
原则:简单的一行条件用后置,复杂多分支用普通 if/end。
3. unless:if 的反面
unless 是 if ! 的语法糖,语义是"除非":
# unless = if 的反面:除非满足,否则执行
unless user.admin?
puts "请登录管理员账号"
end
# 等价于
if !user.admin?
puts "请登录管理员账号"
end
# 新手建议:unless 只用在"没有 else 分支"的简单情况
# 有 else 时用 if 更清晰
unless x
puts "x 为 nil 或 false"
else
puts "x 为真" # ⚠️ 这种写法可读性差,改用 if
end新手口诀:unless 只用在没有 else 的简单情况。一旦有 else 分支,改用 if !cond 更可读。
4. case/when(Ruby 的 switch)
多分支选择,比 if/elsif 链更清晰:
# case/when:多分支选择(类似其他语言的 switch)
grade = "B"
case grade
when "A"
puts "优秀"
when "B"
puts "良好" # 这条
when "C"
puts "及格"
when "D", "F" # 多个值用逗号
puts "不及格"
else
puts "未知"
end
# case 还能省略目标,直接写条件
age = 25
case
when age < 18
puts "未成年"
when age < 60
puts "青年" # 这条
else
puts "老年"
endRuby 的 case 比其他语言的 switch 强大,因为它的匹配用的是 === 运算符,而 Ruby 里 === 是被各类型重载的:
- Range:
(1..10) === 5为 true(范围包含判断)。 - Class:
String === "hi"为 true(类型判断)。 - Regexp:
/^\\d+$/ === "123"为 true(正则匹配)。 - Proc:
->(x){ x > 5 } === 10为 true(调用 Proc)。
所以 case 能优雅地配合范围、类型、正则:
# case 配合 Range 很优雅
score = 85
case score
when 90..100
puts "优秀"
when 80..89
puts "良好" # 这条
when 60..79
puts "及格"
when 0..59
puts "不及格"
end
# case 判断类型(=== 机制)
case "hello"
when String
puts "是字符串"
when Integer
puts "是整数"
end5. while 循环
# while:先判条件再循环
i = 0
while i < 5
puts i
i += 1
end
# 输出 0 1 2 3 4
# begin/end while:至少执行一次(类似 do/while)
count = 0
begin
puts count
count += 1
end while count < 3begin/end while 是 Ruby 版的 do/while——先执行一次再判断条件。这种写法在实际项目里很少见,大家更倾向用 loop 配 break。
6. until 循环
until 是 while 的反面——直到条件为真才停:
# until:while 的反面,直到条件为真才停
i = 5
until i == 0
puts i
i -= 1
end
# 输出 5 4 3 2 1
# 后置 until
puts "等待中" until ready7. loop 与 break/next
loop 是个无限循环,必须用 break 退出:
# loop 是 Kernel 方法:无限循环,必须靠 break 退出
i = 0
loop do
break if i >= 5
puts i
i += 1
end
# 配合 next 跳过本次
5.times do |n|
next if n.even?
puts n # 只输出奇数:1 3
end
# redo:重新执行本次(慎用)三个循环控制关键字:
- break:完全退出循环。
- next:跳过本次,进入下一次(类似 continue)。
- redo:重新执行本次(很少用)。
- retry:重新执行整个循环(更少用,常用于异常重试)。
8. 迭代器:Ruby 的循环主力
Ruby 社区几乎不用 for,而是用迭代器方法——它们更优雅、更接近"描述要做什么"而非"怎么做":
# Ruby 社区几乎不用 for,而是用迭代器方法
# times:重复 n 次
3.times { |i| puts i } # 0 1 2
# upto / downto:从某数到某数
1.upto(5) { |i| puts i } # 1 2 3 4 5
5.downto(1) { |i| puts i } # 5 4 3 2 1
# each:遍历集合(最常用)
[10, 20, 30].each { |x| puts x }
# step:按步长
0.step(10, 2) { |i| puts i } # 0 2 4 6 8 10
# for 写法(也支持但少用)
for x in [1, 2, 3] do
puts x
end为什么不用 for?因为 for 在 Ruby 里其实只是 each 的语法糖,且不创建新作用域(for 里定义的变量在外面也能访问),容易出 bug。所以社区一致用迭代器。
9. 谁优先:迭代器 vs 循环?
- 遍历集合:用
each/map/select。 - 重复 n 次:用
n.times。 - 从 a 数到 b:用
a.upto(b)/a.downto(b)。 - 无限循环:用
loop配break。 - 条件循环:用
while/until(少见,通常能改成迭代器)。
90% 的循环场景,都能用迭代器更优雅地解决。这是 Ruby 与 C/Java 最大的"思维差异"。
小结
本章你学会了 Ruby 全部控制流结构。重点是理解迭代器优先于循环——这是 Ruby 的核心哲学之一。下一篇我们看方法,把"一段可复用的逻辑"封装起来。
← 上一篇 Ruby 运算符
下一篇 Ruby 方法 →