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

6yoyoihd  于 2023-10-17  发布在  Ruby
关注(0)|答案(8)|浏览(128)

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

aydmsdu9

aydmsdu91#

一个不同之处在于他们处理论点的方式。使用proc {}Proc.new {}创建proc是等效的。但是,使用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指出的,在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

gxwragnw

gxwragnw2#

procs和prodas之间的真实的区别与控制流关键字有关。我说的是returnraisebreakredoretry等。这些控制词。假设你在proc中有一个return语句。当你调用proc时,它不仅会把你从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和prodas中处理控制流关键字的方式是它们之间的主要区别

wpcxdonn

wpcxdonn3#

只有两个主要区别。

  • 首先,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!"

看看proc如何说“ bat 侠会赢!“,这是因为它会立即返回,而不会返回到batman_ironman_proc方法。
然而,我们的lambda在被调用后会返回到方法中,因此方法返回它评估的最后一段代码:“钢铁侠必胜!“

hjzp0vay

hjzp0vay4#

#流程示例

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和propdas之间的区别之前,有一点很重要,那就是它们都是Proc对象。

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

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

然而,阿罗达斯是一个不同的“风味”的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)

相反,proc不关心是否传递了错误数量的参数。

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语句返回proc的值,请使用lambda。
引用自here

nhhxz33t

nhhxz33t5#

一般来说,lambdas比pros更直观,因为它们更类似于方法。他们对arity的要求非常严格,当你调用return时,他们只是退出。出于这个原因,许多Rubyists使用lambda作为首选,除非他们需要pros的特定特性。

Procs:Proc类的对象。与块一样,它们在定义它们的范围内进行评估。
**Lambdas:**也是Proc类的对象,但与常规proc有细微的不同。

它们是类似于块和proc的闭包,因此它们在定义它们的范围中被评估。
创建流程

a = Proc.new { |x| x 2 }

创建lambda

b = lambda { |x| x 2 }
cmssoen2

cmssoen26#

这是另一种理解这一点的方式。
块是附加到对对象的方法的调用的代码块。在下面的例子中,self是一个匿名类的示例,它继承自Rails框架中的RoundView::Base(它本身包括许多帮助器模块)。卡片是我们调用自我的方法。我们向方法传递一个参数,然后我们总是将块附加到方法调用的末尾:

self.card :contacts do |c|
  // a chunk of valid ruby code    
end

好的,我们将一段代码传递给一个方法。但是我们如何利用这个块呢?一种选择是将代码块转换为对象。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

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

def add(&block)
  block
end

l3 = add { |a| a + 1 }
l3.call(1)
=> 2

这很重要当你将一个块传递给一个方法并使用&转换它时,它创建的对象使用Proc.new来进行转换。
请注意,我避免使用“proc”作为选项。这是因为在Ruby 1.8中,它与lambda相同,在Ruby 1.9中,它与www.example.com相同Proc.new,在所有Ruby版本中都应该避免。
然后你会问lambda和Proc.new?有什么区别
首先,在参数传递方面,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 +

其次,lambda和Proc.new处理return关键字的方式不同。当你在Proc.new中执行返回时,它实际上是从封闭的方法,也就是周围的上下文返回的。当你从lambda块返回时,它只是从块返回,而不是从封闭的方法返回。基本上,它从对块的调用中退出,并继续执行封闭方法的其余部分。

> def add(a,b)
  l = Proc.new { return a + b}
  l.call
  puts "now exiting method"
end
> add(1,1)
=> 2  # NOTICE it never prints the message "now exiting method"

> def add(a,b)
  l = lambda { return a + b }
  l.call
  puts "now exiting method"
end
> add(1,1)
=> now exiting method  # NOTICE this time it prints the message "now exiting method"

为什么会有这种行为差异呢?原因是因为在www.example.com中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

我们期望当我们在迭代器内部调用return时,它将从封闭方法返回。请记住,传递给迭代器的块使用www.example.com转换为对象Proc.new,这就是为什么当我们使用return时,它将退出封闭方法。
你可以把匿名方法看作是匿名方法,它们把单独的代码块隔离成一个对象,可以像方法一样对待。最后,将lambda视为一个异常方法,而Proc.new则视为内联代码。

xcitsw88

xcitsw887#

关于ruby guides的有用文章:blocks, procs & lambdas
Procs从当前方法返回,而prodas从lambda本身返回。
proc不关心参数的正确数量,而prod则会引发异常。

kqhtkvqz

kqhtkvqz8#

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

相关问题