Ruby 中使用 Lambda 和 Proc 保存块

在Block的章节中,我们学习了在 Ruby 中学习了创建块了两种方式:{}以及do...end和如何在方法使用yield以及使用call来调用一个块。今天我们学习将块保存到变量的两种形式:Labmbda 和Proc。

1. Proc

1.1 定义

Proc 有两种表达方式:

say_something = Proc.new { puts "This is a proc" }

另外一种是:

say_something = proc { puts "This is a proc" }

1.2 调用

我们使用call来执行 Proc 的代码。

实例:

say_something = -> { puts "This is a proc" }
say_something.call

# ---- 输出结果 ----
This is a proc

注意事项:Proc有很多种调用方式,但是我们只使用call,不使用其它的。

实例:

my_proc = -> { puts "Proc called" }
my_proc.call
my_proc.()
my_proc[]
my_proc.===
  
# ---- 输出结果 ----
Proc called
Proc called
Proc called
Proc called

1.3 接收参数

第一种写法接收参数的形式为:

times_two = Proc.new {|x| x * 2 }
times_two.call(10)

# ---- 输出结果 ----
20

第二种形式为:

times_two = proc {|x| x * 2 }
times_two.call(10)

# ---- 输出结果 ----
20

2. Lambda

2.1 定义

Lambda 有两种表达方式:

say_something = -> { puts "This is a lambda" }

另外一种是:

say_something = lambda { puts "This is a lambda" }

Tips->这种写法Ruby 1.9 以上版本才支持。

2.2 调用

定义 Lambda 不会在其中运行代码,就像定义方法不会运行该方法一样,您需要为此使用call方法。

实例:

say_something = -> { puts "This is a lambda" }
say_something.call

# ---- 输出结果 ----
This is a lambda

注意事项:Lambda同样有很多种调用方式,但是我们依然只使用call

实例:

my_lambda = -> { puts "Lambda called" }
my_lambda.call
my_lambda.()
my_lambda[]
my_lambda.===
  
# ---- 输出结果 ----
Lambda called
Lambda called
Lambda called
Lambda called

2.3 接收参数

Lambda 也可以接受参数。

实例:

times_two = ->(x) { x * 2 }
times_two.call(10)

# ---- 输出结果 ----
20

注意,两种 Lambda 的参数表现形式是不同的。

times_two = lambda {|x| x * 2 }
times_two.call(10)

# ---- 输出结果 ----
20

如果将错误数量的参数传递给 Lambda,则将引发异常,就像常规方法一样。

实例:

times_two = ->(x) { x * 2 }
times_two.call()

# ---- 输出结果 ----
ArgumentError (wrong number of arguments (given 0, expected 1)) 

3. 比较 Proc 和 Lambda

3.1 创建形式不同,调用方法相同。

Lambda 和 Proc 本质上都Proc类的对象,Proc 类有一个实例方法名为lambda?

puts proc { }.class
puts Proc.new {}.class
puts lambda {}.class
puts -> {}.class
  
# ---- 输出结果 ----
Proc
Proc
Proc
Proc

3.2 对于接收参数后是否传值反应不同

Proc 不在意是否真正传入参数,Lambda 要求调用时传入的参数必须和接收的参数保持一致,否则会抛出异常。

3.3 对于return语句的处理

Lambda 中使用return语句和常规方法一样。

实例:

my_lambda = lambda { return 1 } 
puts "Lambda result: #{my_lambda.call}"

# ---- 输出结果 ----
Lambda result: 1

Proc 则在当前上下文中使用return。相当于在调用位置执行return

实例:

my_proc = proc { return 1 } 
puts "Proc result: #{my_proc.call}"
  
# ---- 没有输出结果 ----  

相当于:

puts "Proc result: #{return 1}" 

# ---- 没有输出结果 ----

Tips:在低于Ruby 2.5 版本中,我们这种写法会抛出异常

unexpected return (LocalJumpError)。

所以我们在 Proc 中使用return的时候,一般结合方法来使用。

def proc_method
  my_proc = proc { return 1 } 
  my_proc.call
end

puts "Proc result: #{proc_method}"
  
# ---- 输出结果 ---- 
Proc result: 1

4. 小结

本章节我们学习了将块保存到变量的两种形式 Lambda 和 Proc,可以使用procProc.new创建Proc,可以使用lambda->创建 Lambda,调用它们要使用call,了解了 Proc 和 Lambda 本质都是一样的,都是Proc类的实例。以及如何接收参数,对return语句的处理。