什么时候你会使用其中一种而不是另一种?


当前回答

一篇关于ruby指南:blocks, procs和lambdas的有用文章

Procs从当前方法返回,而lambdas从lambda本身返回。 Procs不关心参数的正确数量,而lambdas则会引发异常。

其他回答

一篇关于ruby指南:blocks, procs和lambdas的有用文章

Procs从当前方法返回,而lambdas从lambda本身返回。 Procs不关心参数的正确数量,而lambdas则会引发异常。

一个不同之处在于它们处理参数的方式。使用proc{}和proc .new{}创建proc是等价的。但是,使用lambda{}提供了一个检查传递给它的参数数量的过程。从ri Kernel#lambda:

等价于Proc.new,除了结果Proc对象检查调用时传递的参数数量。

一个例子:

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)

此外,正如Ken指出的那样,在lambda中使用return将返回该lambda的值,而在proc中使用return则从外围块返回。

lambda { return :foo }.call # => :foo
return # => LocalJumpError: unexpected return
Proc.new { return :foo }.call # => LocalJumpError: unexpected return

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

procs和lambdas之间的真正区别在于控制流关键字。我说的是return, raise, break, redo, retry等等——这些控制词。假设你在一个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

final函数放入方法中,从未执行过,因为当我们调用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

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

证明一下

p = Proc.new { |x| puts x*2 }
[1,2,3].each(&p)              # The '&' tells ruby to turn the proc into a block 

proc = Proc.new { puts "Hello World" }
proc.call

# Lambda例子

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

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

Procs和Lambdas之间的区别

在讨论procs和lambdas之间的区别之前,有必要提到它们都是Proc对象。

proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }

proc.class # returns 'Proc'
lam.class  # returns 'Proc'

然而,lambdas是procs的另一种“风格”。这个细微的差别在返回对象时显示出来。

proc   # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam    # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'

1. Lambdas检查参数的数量,而procs不检查

lam = lambda { |x| puts x }    # creates a lambda that takes 1 argument
lam.call(2)                    # prints out 2
lam.call                       # ArgumentError: wrong number of arguments (0 for 1)
lam.call(1,2,3)                # ArgumentError: wrong number of arguments (3 for 1)

相反,procs并不关心传入的参数数量是否错误。

proc = Proc.new { |x| puts x } # creates a proc that takes 1 argument
proc.call(2)                   # prints out 2
proc.call                      # returns nil
proc.call(1,2,3)               # prints out 1 and forgets about the extra arguments

2. Lambdas和procs对' return '关键字的处理是不同的

lambda代码中的' return '触发了lambda代码外部的代码

def lambda_test
  lam = lambda { return }
  lam.call
  puts "Hello world"
end

lambda_test                 # calling lambda_test prints 'Hello World'

proc内部的' return '触发正在执行proc的方法外部的代码

def proc_test
  proc = Proc.new { return }
  proc.call
  puts "Hello world"
end

proc_test                 # calling proc_test prints nothing

回答你的另一个问题,什么时候用哪个?正如他提到的,我会关注@jtbandes

对于大多数快速使用,它们是一样的,但是如果你想要自动的 严格的参数检查(有时也可以帮助 调试),或者如果需要使用return语句返回 的值,使用lambda。

原贴于此

proc和lambda之间的区别在于,proc只是一份代码的副本,参数被依次替换,而lambda则像其他语言一样是一个函数。(返回行为,参数检查)