ZetCode

Ruby yield 关键字

最后修改日期:2025 年 4 月 27 日

本教程将解释如何使用 Ruby 的 yield 关键字。yield 关键字是与 Ruby 中的代码块交互的基础。

yield 关键字将控制权从方法转移到其关联的代码块。它允许方法接受可以在方法上下文中执行的代码块。

带有 yield 的代码块支持迭代、资源管理和回调等强大模式。它们是 Ruby 表达性语法的一个关键特性。

基础 yield 示例

这个简单的示例演示了 yield 关键字的基本用法。该方法将控制权交给其代码块。

basic_yield.rb
def greet
  puts "Before yield"
  yield
  puts "After yield"
end

greet { puts "Hello from the block!" }

yield 关键字执行传递给 greet 方法的代码块。输出显示了方法和代码块之间的执行流程。

向 yield 传递参数

yield 可以将参数传递给其代码块。代码块在竖线 | | 之间接收这些参数。

yield_params.rb
def calculate(a, b)
  puts "Calculating..."
  result = yield(a, b)
  puts "Result: #{result}"
end

calculate(5, 3) { |x, y| x * y }
calculate(10, 2) { |x, y| x / y }

该方法通过 yield 将参数传递给代码块。不同的代码块可以使用相同的参数执行不同的操作。

使用 block_given? 检查代码块

使用 yield 的方法应该检查是否提供了代码块。block_given? 方法可以防止在没有代码块时出现错误。

block_given.rb
def process
  if block_given?
    yield
  else
    puts "No block provided"
  end
end

process { puts "Processing..." }
process

第一次调用执行代码块,第二次则优雅地处理了缺少代码块的情况。这使得方法更加健壮。

实现自定义迭代器

yield 支持创建自定义迭代器。此示例模仿了 Ruby 的数组 each 方法。

custom_iterator.rb
def my_each(array)
  i = 0
  while i < array.length
    yield(array[i])
    i += 1
  end
  array
end

my_each([1, 2, 3]) { |x| puts x * 2 }

该方法将数组的每个元素 yield 给代码块。代码块处理每个元素,展示了 Ruby 内置迭代器的工作原理。

资源管理模式

yield 非常适合资源管理模式。这可以确保资源被正确地分配和释放。

resource_management.rb
def with_file(filename)
  file = File.open(filename, 'w')
  yield(file)
ensure
  file.close if file
end

with_file('output.txt') do |f|
  f.puts "First line"
  f.puts "Second line"
end

该方法负责文件的打开和关闭,而代码块负责写入内容。ensure 子句保证即使发生错误,文件也会被关闭。

Yield 配合多个代码块

方法可以多次 yield 同一个代码块。这可以创建灵活的执行模式。

multiple_yields.rb
def stages
  puts "Stage 1"
  yield("start")
  puts "Stage 2"
  yield("middle")
  puts "Stage 3"
  yield("end")
end

stages { |phase| puts "Processing #{phase} phase" }

该方法在不同阶段 yield 控制权,并传递阶段信息。代码块会执行多次,并带有不同的参数。

进阶:Yield 配合 Enumerator

这个进阶示例展示了 yield 如何创建枚举器。这使得序列的延迟计算成为可能。

enumerator.rb
def fibonacci_sequence
  return enum_for(:fibonacci_sequence) unless block_given?
  
  a, b = 0, 1
  loop do
    yield a
    a, b = b, a + b
  end
end

# Get first 10 Fibonacci numbers
fibonacci_sequence.take(10).each { |x| puts x }

该方法会无限生成斐波那契数列。如果不提供代码块,它将返回一个用于延迟计算的枚举器。如果提供了代码块,它将 yield 每个数字。

来源

Ruby 关键字文档

本教程通过实际示例讲解了 Ruby 的 yield 关键字,展示了代码块、迭代器、资源管理和枚举器。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Ruby 教程