Ruby中的proc和lambda有什么区别?

Tom Lehman 162 ruby

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

jtbandes.. 245

一个区别在于它们处理参数的方式.使用proc {}和创建一个Proc.new {}等效的proc .但是,using lambda {}会给你一个proc来检查传递给它的参数的数量.来自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指出的那样,return在lambda内部使用返回该lambda的值,但是return在proc中使用从封闭块返回.

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

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

  • 是否准确地说lambdas非常类似于方法(检查参数和返回将从它们返回),而procs非常类似于块(参数未被检查,返回将从包含方法或lambda返回)? (6认同)

用户甲.. 67

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

方法中的最后一个puts从未执行过,因为当我们调用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中处理控制流关键字的方式是它们之间的主要区别