在 Ruby 中,blok,proc 和 lambda 有什么区别?

bloks,procs和lambdas是什么?

Coder Talk:Ruby中_closures_的示例。原文编程

Plain old english:咱们想要运行的代码分组方法。闭包

# Block Examples

[1,2,3].each { |x| puts x*2 } # blok is in between the curly braces

[1,2,3].each do |x|
  puts x*2 # blok is everything between the do and end
end

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

proc = Proc.new { puts "Hello World" }
proc.call # The body of the Proc object gets executed when called

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

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

虽然看起来这些都很是类似,但我将在下面介绍一些细微差异。app

Blocks和Procs之间的差别

Procs are objects, blocks are notcurl

proc(注意小写的p)是Proc类的一个实例。ide

p = Proc.new { puts "Hello World" }

这让咱们能够在其上调用方法并将其分配给变量。 Procs也能够本身回归。函数

p.call # prints 'Hello World'
p.class # returns 'Proc'
a = p # a now equals p, a Proc instance
p # returns a proc object '#<Proc:0x007f96b1a60eb0@(irb):46>'

相比之下,blok只是方法调用的 syntax的一部分。 它并不表明任何独立的东西,只能出如今参数列表中。学习

{ puts "Hello World"} # syntax error  
a = { puts "Hello World"} # syntax error
[1,2,3].each {|x| puts x*2} # only works as part of the syntax of a method call
  1. At most one block can appear in an argument list

相反,您能够将多个过程传递给方法。ui

def multiple_procs(proc1, proc2)
  proc1.call
  proc2.call
end

a = Proc.new { puts "First proc" }
b = Proc.new { puts "Second proc" }

multiple_procs(a,b)

Procs和Lambdas之间的差别

在得出进入procs和lambdas之间的差别以前,重要的是要提到它们都是Proc对象。url

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

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

然而,lambdas是一种不一样的“味道"。 返回对象时会显示这种细微差异。code

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

(lambda)符号提醒一下,虽然procs和lambdas很是类似,即便是Proc类的两个实例,它们也略有不一样。 如下是主要差别。

Lambdas check the number of arguments, while procs do not

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.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

如上所示,若是传递了错误数量的参数,则procs不会出错并引起错误。 若是proc须要参数但没有传递参数,则proc返回nil。 若是传递的参数太多而忽略了额外的参数。

  1. Lambdas and procs treat the ‘return’ keyword differently

lambda中的'return'会在lambda代码以外触发代码

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

lambda_test yyy188zzzcalling lambda_test prints 'Hello World'

proc中的'return'触发执行proc的方法以外的代码

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

proc_test yyy188zzzcalling proc_test prints nothing

什么是封闭?

Coder Talk:'函数或对函数的引用以及引用环境。 与普通函数不一样,闭包容许函数访问non-local变量,即便在其直接词法范围以外调用它。' - Wikipedia

Plain old english:相似于一个手提箱,它是一组代码,当打开(即调用)时,包含打包它时所包含的内容(即建立它)。

# Example of Proc objects preserving local context

def counter
  n = 0
  return Proc.new { n+= 1 }
end

a = counter
a.call # returns 1
a.call # returns 2

b = counter
b.call # returns 1

a.call # returns 3

Background第1部分:Lambda微积分和匿名函数

Lambda的名字源于20世纪30年代引入的一种微积分,以帮助研究数学的基础。 Lambda演算经过简化其语义,有助于使可计算函数更容易学习。 这些简化中最相关的是“匿名"处理函数,这意味着没有给函数赋予明确的名称。

sqsum(x,y) = x*x + y*y #<-- normal function
(x,y) -> x*x + y*y #<-- anonymous function

通常来讲,在编程中,术语lambda指的是匿名函数。 这些匿名函数在某些语言(即Javascript)中是很是常见和明确的,而在其余语言中是隐含的(即Ruby)。

Background第2部分:名称过程来自何处

Proc是程序的简称,程序是一组打包做为执行特定任务的单元的指令。 在不一样的语言中,这些能够称为函数,例程,方法或通用术语可调用单元。 它们一般被屡次调用,并在程序中屡次调用。

Summary差别

Procs are objects, blocks are not

  1. At most one block can appear in an argument list

Lambdas check the number of arguments, while procs do not
Lambdas and procs treat the ‘return’ keyword differently

相关文章
相关标签/搜索