文章

💎 Ruby 闭包

介绍 Ruby 中闭包的实现及其使用方式

由于 Ruby 自身的语法特性,允许方法可以不带括号直接调用,这使得无法在方法内部返回方法。再加上 Ruby 方法内无法访问方法外的变量,导致 Ruby 中的方法不是一等公民,因此无法直接使用方法来实现闭包。

在 Ruby 中,一等公民是 Proc 对象,因此要实现闭包,需使用 Ruby 的 Proclambda 来实现。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def test_by_Proc(x)
  return Proc.new {|y| x + y}
end

def test_by_lambda(x)
  return ->(y) {x + y}
end

def test_by_method1(x)
  def closure(y)
    y
  end
  return method(:closure)
end

# 下面是错误的
def test_by_method2(x)
  def closure(y)
    x + y   # 内部 def 不能访问外部 def 的局部变量 x
  end
  return method(:closure)
end

调用闭包

注意,返回闭包后(即 Proc 对象),通过 call 方法或其它同义词方法进行调用执行。例如下面的调用是等价的:

1
2
3
4
puts test_by_Proc(3).call(4)
puts test_by_Proc(3)[4]
puts test_by_Proc(3).(4)
puts test_by_Proc(3).yield(4)

变量作用域

最后需要注意的是 Ruby 中的变量作用域问题。Ruby 采用的是词法作用域,它定义于何处,将见到何处的变量,这与其调用位置无关。

1
2
3
4
5
6
7
8
9
10
11
def func1(pr)
  a = "hello"
  puts a
  pr.call
end

a = "world"
pr = Proc.new {puts a}
a = "WORLD"
pr.call
func1(pr)

输出结果

1
2
3
WORLD
hello
WORLD

总结

在 Ruby 中实现闭包的关键是利用 Proclambda,而非直接通过方法。同时,需要理解 Ruby 的词法作用域,以便更好地控制变量的可见性和访问。

本文由作者按照 CC BY 4.0 进行授权