Ruby块、Proc和LambdaSkill ruby-blocks-procs-lambdas

Ruby 块、Proc 和 Lambda 是 Ruby 编程语言的核心功能编程特性,用于实现闭包、高阶函数等模式,提升代码表达性和优雅性。适用于软件开发和后端工程。关键词包括 Ruby 编程、功能编程、块、Proc、Lambda、闭包、高阶函数、后端开发。

后端开发 0 次安装 0 次浏览 更新于 3/25/2026

name: ruby-blocks-procs-lambdas user-invocable: false description: 用于处理 Ruby 块、proc、lambda 和功能编程模式,包括闭包和高阶函数。 allowed-tools:

  • Bash
  • Read
  • Write
  • Edit

Ruby 块、Proc 和 Lambda

通过块、proc 和 lambda 掌握 Ruby 的功能编程特性。这些是 Ruby 表达性和优雅风格的基础。

基本块语法

# 使用 do...end 的块(多行)
[1, 2, 3].each do |num|
  puts num * 2
end

# 使用 {...} 的块(单行)
[1, 2, 3].each { |num| puts num * 2 }

向块让步

def repeat(times)
  times.times do
    yield  # 执行块
  end
end

repeat(3) { puts "Hello" }

# 带块参数
def greet
  yield("World")
end

greet { |name| puts "Hello, #{name}!" }

块参数

def process_data(data)
  result = yield(data)
  puts "Result: #{result}"
end

process_data(10) { |x| x * 2 }  # 结果: 20

检查块是否存在

def optional_block
  if block_given?
    yield
  else
    puts "未提供块"
  end
end

optional_block { puts "块已执行" }
optional_block

块局部变量

x = 10

[1, 2, 3].each do |num; local_var|
  local_var = num * 2  # local_var 仅存在于块中
  puts local_var
end

puts x  # 10(未改变)

Proc

创建 Proc

# 使用 Proc.new
my_proc = Proc.new { |x| x * 2 }
puts my_proc.call(5)  # 10

# 使用 proc 方法(某些版本中已弃用)
my_proc = proc { |x| x * 2 }

# 使用 ->(Proc 的刺刀 lambda 语法)
my_proc = ->(x) { x * 2 }

Proc 特性

# Proc 不关心参数数量
flexible_proc = Proc.new { |x, y| "x: #{x}, y: #{y}" }
puts flexible_proc.call(1)     # x: 1, y:
puts flexible_proc.call(1, 2, 3)  # x: 1, y: 2(忽略额外参数)

# Proc 从包含方法返回
def proc_return
  my_proc = Proc.new { return "来自 proc" }
  my_proc.call
  "proc 之后"  # 从未到达
end

puts proc_return  # "来自 proc"

将 Proc 作为参数传递

def execute_proc(my_proc)
  my_proc.call
end

greeting = Proc.new { puts "来自 proc 的问候!" }
execute_proc(greeting)

将块转换为 Proc

def method_with_proc(&block)
  block.call
end

method_with_proc { puts "块已转换为 proc" }

Lambda

创建 Lambda

# 使用 lambda 关键字
my_lambda = lambda { |x| x * 2 }

# 使用 ->(刺刀 lambda)
my_lambda = ->(x) { x * 2 }

# 多行刺刀 lambda
my_lambda = ->(x) do
  result = x * 2
  result + 1
end

puts my_lambda.call(5)  # 11

Lambda 特性

# Lambda 强制执行参数数量
strict_lambda = ->(x, y) { x + y }
# strict_lambda.call(1)     # ArgumentError
strict_lambda.call(1, 2)    # 有效

# Lambda 返回给调用者
def lambda_return
  my_lambda = -> { return "来自 lambda" }
  my_lambda.call
  "lambda 之后"  # 这会被到达
end

puts lambda_return  # "lambda 之后"

带多个参数的 Lambda

add = ->(x, y) { x + y }
multiply = ->(x, y, z) { x * y * z }

puts add.call(3, 4)         # 7
puts multiply.call(2, 3, 4) # 24

# 默认参数
greet = ->(name = "World") { "Hello, #{name}!" }
puts greet.call           # "Hello, World!"
puts greet.call("Ruby")   # "Hello, Ruby!"

Proc 与 Lambda 对比

# 参数处理
my_proc = Proc.new { |x, y| puts "x: #{x}, y: #{y}" }
my_lambda = ->(x, y) { puts "x: #{x}, y: #{y}" }

my_proc.call(1)     # 有效: x: 1, y:
# my_lambda.call(1) # ArgumentError

# 返回行为
def test_return
  proc_test = Proc.new { return "proc 返回" }
  lambda_test = -> { return "lambda 返回" }

  proc_test.call   # 从方法返回
  "结束"            # 从未到达
end

def test_lambda
  lambda_test = -> { return "lambda 返回" }
  lambda_test.call # 从 lambda 返回
  "结束"            # 这会被到达
end

# 检查是否为 lambda
my_proc = Proc.new { }
my_lambda = -> { }

puts my_proc.lambda?   # false
puts my_lambda.lambda? # true

闭包

def multiplier(factor)
  ->(x) { x * factor }
end

times_two = multiplier(2)
times_three = multiplier(3)

puts times_two.call(5)    # 10
puts times_three.call(5)  # 15

# 闭包捕获变量
def counter
  count = 0

  increment = -> { count += 1 }
  decrement = -> { count -= 1 }
  value = -> { count }

  [increment, decrement, value]
end

inc, dec, val = counter
inc.call
inc.call
puts val.call  # 2
dec.call
puts val.call  # 1

方法对象

class Calculator
  def add(x, y)
    x + y
  end
end

calc = Calculator.new
add_method = calc.method(:add)
puts add_method.call(3, 4)  # 7

# 将方法转换为 proc
add_proc = calc.method(:add).to_proc
puts add_proc.call(5, 6)  # 11

符号到 Proc

# & 将符号转换为 proc
numbers = [1, 2, 3, 4, 5]

# 这些是等价的:
numbers.map { |n| n.to_s }
numbers.map(&:to_s)

# 适用于任何方法
["hello", "world"].map(&:upcase)  # ["HELLO", "WORLD"]
[1, 2, 3].select(&:even?)         # [2]

高阶函数

def compose(f, g)
  ->(x) { f.call(g.call(x)) }
end

double = ->(x) { x * 2 }
square = ->(x) { x * x }

double_then_square = compose(square, double)
puts double_then_square.call(3)  # 36 (3 * 2 = 6, 6 * 6 = 36)

柯里化

# 手动柯里化
add = ->(x) { ->(y) { x + y } }
add_five = add.call(5)
puts add_five.call(3)  # 8

# 内置柯里化
multiply = ->(x, y, z) { x * y * z }
curried = multiply.curry
times_two = curried.call(2)
times_two_three = times_two.call(3)
puts times_two_three.call(4)  # 24

# 部分应用
puts curried.call(2, 3).call(4)  # 24

实用模式

惰性求值

def lazy_value
  puts "计算昂贵值..."
  42
end

# 包装在 lambda 中以进行惰性求值
lazy = -> { lazy_value }

puts "调用前"
result = lazy.call  # 仅在此处计算
puts result

回调模式

class Button
  def initialize
    @on_click = []
  end

  def on_click(&block)
    @on_click << block
  end

  def click
    @on_click.each(&:call)
  end
end

button = Button.new
button.on_click { puts "按钮已点击!" }
button.on_click { puts "另一个处理器" }
button.click

策略模式

class Sorter
  def initialize(strategy)
    @strategy = strategy
  end

  def sort(array)
    @strategy.call(array)
  end
end

ascending = ->(arr) { arr.sort }
descending = ->(arr) { arr.sort.reverse }

sorter = Sorter.new(ascending)
puts sorter.sort([3, 1, 2])  # [1, 2, 3]

sorter = Sorter.new(descending)
puts sorter.sort([3, 1, 2])  # [3, 2, 1]

记忆化

def memoize(&block)
  cache = {}
  ->(arg) do
    cache[arg] ||= block.call(arg)
  end
end

expensive_operation = memoize do |n|
  puts "为 #{n} 计算..."
  n * n
end

puts expensive_operation.call(5)  # 为 5 计算... 25
puts expensive_operation.call(5)  # 25(已缓存)

最佳实践

  1. 对简单迭代和一次性闭包使用块
  2. 对严格的参数检查和可返回闭包使用 lambda
  3. 对灵活的参数处理使用 proc(罕见情况)
  4. 优先使用 -> 语法(更简洁)
  5. 对集合的简单方法调用使用 &:symbol
  6. 利用闭包进行封装和数据隐私
  7. 在向可选块让步前使用 block_given?

反模式

不要使用 Proc.new 实现严格行为 - 改用 lambda ❌ 不要忽略返回行为 - 理解 proc 与 lambda 的区别 ❌ 不要过度使用闭包 - 可能导致内存泄漏 ❌ 不要创建深度嵌套的 lambda - 难以阅读和调试 ❌ 不要忘记处理缺失的块 - 用 block_given? 检查

相关技能

  • ruby-oop - 用于理解方法上下文
  • ruby-metaprogramming - 用于动态块/proc 使用
  • ruby-standard-library - 用于使用块的 Enumerable 方法