Ruby循环控制 #

一、循环控制概述 #

Ruby提供了多种控制循环执行的语句。

语句 描述
break 终止循环
next 跳过当前迭代
redo 重新执行当前迭代
retry 重新开始循环

二、break #

2.1 基本用法 #

ruby
i = 0

while true
  puts i
  i += 1
  break if i >= 5
end

2.2 在迭代器中使用 #

ruby
[1, 2, 3, 4, 5].each do |n|
  break if n > 3
  puts n
end

2.3 带返回值 #

ruby
result = [1, 2, 3, 4, 5].each do |n|
  break n * 2 if n > 3
end

puts result

2.4 多值返回 #

ruby
result = loop do
  break 1, 2, 3
end

result

2.5 嵌套循环中的break #

ruby
for i in 1..3
  for j in 1..3
    puts "#{i}, #{j}"
    break if j == 2
  end
end

2.6 实用示例 #

ruby
def find_first(items, condition)
  items.each do |item|
    return item if condition.call(item)
  end
  nil
end

find_first([1, 2, 3, 4, 5], ->(n) { n > 3 })

三、next #

3.1 基本用法 #

ruby
(1..10).each do |n|
  next if n.even?
  puts n
end

3.2 在while中使用 #

ruby
i = 0

while i < 10
  i += 1
  next if i.even?
  puts i
end

3.3 带返回值 #

ruby
result = [1, 2, 3, 4, 5].map do |n|
  next nil if n.even?
  n * 2
end

result

3.4 在块中使用 #

ruby
def process_items(items)
  items.each do |item|
    next unless item.valid?

    process(item)
  end
end

3.5 实用示例 #

ruby
def sum_odd_numbers(numbers)
  sum = 0
  numbers.each do |n|
    next unless n.odd?
    sum += n
  end
  sum
end

sum_odd_numbers([1, 2, 3, 4, 5])

四、redo #

4.1 基本用法 #

ruby
i = 0

while i < 3
  i += 1
  puts "i = #{i}"
  redo if i == 2
end

4.2 在迭代器中使用 #

ruby
retries = 0

[1, 2, 3].each do |n|
  puts "处理 #{n}"
  retries += 1
  redo if retries < 2 && n == 2
  retries = 0
end

4.3 输入验证 #

ruby
def get_valid_input
  input = nil

  loop do
    print "请输入数字: "
    input = gets.chomp

    redo unless input.match?(/\A\d+\z/)
    break
  end

  input.to_i
end

4.4 实用示例 #

ruby
def process_with_retry(items)
  items.each do |item|
    attempts = 0

    begin
      puts "处理 #{item}"
      raise "失败" if item == 2 && attempts < 2
      attempts = 0
    rescue
      attempts += 1
      redo if attempts < 3
      puts "跳过 #{item}"
    end
  end
end

五、retry #

5.1 基本用法 #

ruby
def fetch_data(url)
  puts "获取 #{url}"
  raise "网络错误"
end

retries = 0

begin
  fetch_data("https://example.com")
rescue => e
  retries += 1
  if retries < 3
    puts "重试 #{retries}"
    retry
  else
    puts "失败: #{e.message}"
  end
end

5.2 retry vs redo #

ruby
i = 0

while i < 3
  i += 1
  puts "i = #{i}"
  redo if i == 2
end

i = 0

while i < 3
  i += 1
  puts "i = #{i}"
  retry if i == 2
end

5.3 实用示例 #

ruby
def fetch_with_retry(url, max_retries: 3, delay: 1)
  retries = 0

  begin
    response = Net::HTTP.get(URI(url))
    JSON.parse(response)
  rescue => e
    retries += 1
    if retries < max_retries
      puts "重试 #{retries}/#{max_retries}: #{e.message}"
      sleep delay
      retry
    else
      raise "获取失败: #{e.message}"
    end
  end
end

六、catch和throw #

6.1 基本用法 #

ruby
result = catch :done do
  (1..10).each do |i|
    (1..10).each do |j|
      if i * j == 25
        throw :done, [i, j]
      end
    end
  end
  nil
end

result

6.2 跳出嵌套循环 #

ruby
catch :break_all do
  for i in 1..5
    for j in 1..5
      puts "#{i}, #{j}"
      throw :break_all if i == 3 && j == 3
    end
  end
end

6.3 错误处理 #

ruby
def process_data(data)
  catch :invalid do
    data.each do |item|
      throw :invalid, "无效数据: #{item}" unless valid?(item)
      process(item)
    end
    "处理完成"
  end
end

6.4 实用示例 #

ruby
def search_nested(data, target)
  catch :found do
    data.each_with_index do |row, i|
      row.each_with_index do |cell, j|
        throw :found, [i, j] if cell == target
      end
    end
    nil
  end
end

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

search_nested(matrix, 5)
search_nested(matrix, 10)

七、return #

7.1 在块中使用return #

ruby
def find(items, target)
  items.each do |item|
    return item if item == target
  end
  nil
end

find([1, 2, 3, 4, 5], 3)

7.2 return vs break #

ruby
def with_break
  [1, 2, 3, 4, 5].each do |n|
    break n if n > 3
  end
end

def with_return
  [1, 2, 3, 4, 5].each do |n|
    return n if n > 3
  end
end

with_break
with_return

7.3 lambda vs proc #

ruby
my_lambda = -> { return "lambda返回" }
my_proc = Proc.new { return "proc返回" }

def test_lambda
  my_lambda = -> { return "lambda返回" }
  result = my_lambda.call
  "方法继续执行: #{result}"
end

def test_proc
  my_proc = Proc.new { return "proc返回" }
  my_proc.call
  "这行不会执行"
end

test_lambda
test_proc

八、实用示例 #

8.1 重试机制 #

ruby
def with_retry(max_retries: 3)
  retries = 0

  begin
    yield
  rescue => e
    retries += 1
    if retries < max_retries
      puts "重试 #{retries}"
      retry
    else
      raise e
    end
  end
end

with_retry { risky_operation }

8.2 超时处理 #

ruby
require 'timeout'

def with_timeout(seconds)
  Timeout.timeout(seconds) do
    yield
  end
rescue Timeout::Error
  puts "操作超时"
  nil
end

with_timeout(5) { long_running_operation }

8.3 进度跟踪 #

ruby
def process_with_progress(items)
  total = items.length
  processed = 0

  items.each do |item|
    next unless item.valid?

    process(item)
    processed += 1

    if processed % 100 == 0
      puts "进度: #{processed}/#{total}"
    end
  end
end

8.4 批处理 #

ruby
def process_in_batches(items, batch_size: 100)
  items.each_slice(batch_size) do |batch|
    batch.each do |item|
      next unless item.valid?
      process(item)
    end
  end
end

九、最佳实践 #

9.1 选择合适的控制语句 #

ruby
items.each do |item|
  next unless item.valid?
  break if item.stop_signal?
  process(item)
end

9.2 避免过度使用redo/retry #

ruby
# 不推荐
i = 0
while i < 10
  i += 1
  redo if some_condition
end

# 推荐
i = 0
while i < 10
  i += 1
  redo_needed = some_condition
  redo if redo_needed
end

9.3 使用catch/throw处理复杂流程 #

ruby
catch :exit do
  complex_nested_operations
end

十、总结 #

本章我们学习了:

  1. break:终止循环,可带返回值
  2. next:跳过当前迭代
  3. redo:重新执行当前迭代
  4. retry:重新开始循环(通常用于异常处理)
  5. catch/throw:非局部跳转
  6. return:从方法返回

接下来让我们学习Ruby的迭代器!

最后更新:2026-03-27