什么';Ruby中proc和lambda的区别是什么?

什么';Ruby中proc和lambda的区别是什么?,ruby,Ruby,什么时候你会使用一个而不是另一个呢?一个区别在于它们处理参数的方式。使用proc{}和proc.new{}创建proc是等效的。但是,使用lambda{}会为您提供一个检查传递给它的参数数量的过程。从ri内核#lambda: lam = lambda { |x| puts x*2 } [1,2,3].each(&lam) lam = lambda { puts "Hello World" } lam.call 相当于Proc.new,除了生成的Proc对象检查调

什么时候你会使用一个而不是另一个呢?

一个区别在于它们处理参数的方式。使用
proc{}
proc.new{}
创建proc是等效的。但是,使用
lambda{}
会为您提供一个检查传递给它的参数数量的过程。从
ri内核#lambda

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
相当于Proc.new,除了生成的Proc对象检查调用时传递的参数数量之外

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
例如:

p = Proc.new {|a, b| puts a**2+b**2 } # => #<Proc:0x3c7d28@(irb):1>
p.call 1, 2 # => 5
p.call 1 # => NoMethodError: undefined method `**' for nil:NilClass
p.call 1, 2, 3 # => 5
l = lambda {|a, b| puts a**2+b**2 } # => #<Proc:0x15016c@(irb):5 (lambda)>
l.call 1, 2 # => 5
l.call 1 # => ArgumentError: wrong number of arguments (1 for 2)
l.call 1, 2, 3 # => ArgumentError: wrong number of arguments (3 for 2)
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

因此,对于大多数快速使用,它们是相同的,但是如果需要自动严格参数检查(有时也有助于调试),或者如果需要使用
return
语句返回proc的值,使用
lambda

过程和lambda之间的真正区别与控制流关键字有关。我说的是
返回
提高
中断
重做
重试
等等–这些控制字。假设在proc中有一个return语句。当您调用proc时,它不仅会将您从中转储,还会从封闭方法返回,例如:

def my_method
  puts "before proc"
  my_proc = Proc.new do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method

shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_proc # prints "Batman will win!"

def batman_ironman_lambda
  victor = lambda { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_lambda # prints "Iron Man will win!"
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
方法中的最后一个
put
从未执行过,因为当我们调用proc时,其中的
return
将我们排除在方法之外。但是,如果我们将proc转换为lambda,则会得到以下结果:

def my_method
  puts "before proc"
  my_proc = lambda do
    puts "inside proc"
    return
  end
  my_proc.call
  puts "after proc"
end

my_method
shoaib@shoaib-ubuntu-vm:~/tmp$ ruby a.rb
before proc
inside proc
after proc
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

lambda中的返回只会将我们从lambda本身中转储出来,并且封闭方法继续执行。在proc和lambda中处理控制流关键字的方式是它们之间的主要区别

proc和lambda之间的区别在于,proc只是代码的副本,参数依次被替换,而lambda与其他语言中的函数类似。(返回行为、参数检查)

一般来说,lambda比proc更直观,因为它们是
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
与方法更相似。他们对算术非常严格,而且 呼叫return时退出。出于这个原因,许多红宝石爱好者使用lambdas作为 第一选择,除非他们需要procs的特定功能

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
Procs:类的对象
Proc
。与块一样,它们在范围内进行评估 定义它们的地方。 Lambdas:也是类
Proc
的对象,但与常规Proc略有不同。 它们像块和过程一样是闭包,因此它们在 定义它们的范围

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
创建过程

a = Proc.new { |x| x 2 }
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
创建lambda

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

b=lambda{| x | x2
}

这里是理解这一点的另一种方式

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
块是附加到对象上方法调用调用调用的代码块。在下面的示例中,self是一个匿名类的实例,该类继承自Rails框架中的ActionView::Base(它本身包含许多帮助器模块)。卡片是一种我们自己调用的方法。我们向方法传递一个参数,然后始终将块附加到方法调用的末尾:

self.card :contacts do |c|
  // a chunk of valid ruby code    
end
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
好的,我们将一段代码传递给一个方法。但是我们如何利用这个街区呢?一种选择是将代码块转换为对象。Ruby提供了三种将代码块转换为对象的方法

# lambda
> l = lambda { |a| a + 1 }
> l.call(1)
=> 2 

# Proc.new
> l2= Proc.new { |a| a + 1 }
> l2.call(1)
=> 2 

# & as the last method argument with a local variable name
def add(&block)
end
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
在上面的方法中,&将传递给该方法的块转换为对象,并将该对象存储在局部变量块中。事实上,我们可以证明它与lambda和Proc.new具有相同的行为:

def add(&block)
  block
end

l3 = add { |a| a + 1 }
l3.call(1)
=> 2
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
这很重要。将块传递给方法并使用&进行转换时,它创建的对象将使用Proc.new进行转换

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
注意,我避免使用“proc”作为选项。这是因为它与Ruby 1.8相同,与lambda相同,在Ruby 1.9中与Proc.new相同,在所有Ruby版本中都应该避免使用它

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
那么你会问lambda和Proc.new有什么区别

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
首先,在参数传递方面,lambda的行为类似于方法调用。如果传递的参数数量错误,则会引发异常。相反,Proc.new的行为类似于并行赋值。所有未使用的参数将转换为nil:

> l = lambda {|a,b| puts "#{a} + #{b}" }
 => #<Proc:0x007fbffcb47e40@(irb):19 (lambda)> 
> l.call(1)
ArgumentError: wrong number of arguments (1 for 2)

> l2 = Proc.new {|a,b| puts "#{a} + #{b}" }
=> #<Proc:0x007fbffcb261a0@(irb):21> 
> l2.call(1)
1 + 
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
那么为什么会有这种行为差异呢?原因是使用Proc.new,我们可以在封闭方法的上下文中使用迭代器并得出逻辑结论。看看这个例子:

> def print(max)
  [1,2,3,4,5].each do |val|
    puts val
    return if val > max
  end
end
> print(3)
1
2
3
4
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
我们期望当我们在迭代器内调用return时,它将从封闭方法返回。记住,传递给迭代器的块使用Proc.new转换为对象,这就是为什么当我们使用return时,它将退出封闭方法

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

您可以将lambda视为匿名方法,它们将单个代码块隔离到一个可以像方法一样处理的对象中。最后,将lambda视为一个异常方法,而Proc.new视为内联代码。

只有两个主要区别

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
  • 首先,
    lambda
    检查传递给它的参数数量,而
    proc
    则不检查。这意味着
    lambda
    在传递错误数量的参数时将抛出错误,而
    proc
    将忽略意外参数,并将
    nil
    分配给任何缺少的参数
  • 第二,当
    lambda
    返回时,它将控制权传递回调用方法;当
    proc
    返回时,它会立即返回,而不返回调用方法
要了解其工作原理,请查看下面的代码。我们的第一个方法调用
proc
;第二个调用
lambda

def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_proc # prints "Batman will win!"

def batman_ironman_lambda
  victor = lambda { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

puts batman_ironman_lambda # prints "Iron Man will win!"
lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
查看
proc
如何显示“蝙蝠侠将获胜!”,这是因为它会立即返回,而不会返回到蝙蝠侠铁人proc方法

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           

然而,我们的
lambda
在被调用后会返回到该方法中,因此该方法返回它计算的最后一个代码:“钢铁侠将获胜!”

一篇关于ruby指南的有用文章:

lam = lambda { |x| puts x*2 }
[1,2,3].each(&lam)

lam = lambda { puts "Hello World" }
lam.call           
程序检索