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
虽然看起来这些都非常相似,但我将在下面介绍一些细微差别。
Blocks和Procs之间的差异
Procs are objects, blocks are not
proc(注意小写的p)是Proc类的一个实例。
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 '#'
相比之下,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
- At most one block can appear in an argument list
相反,您可以将多个过程传递给方法。
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对象。
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }
proc.class # returns 'Proc'
lam.class # returns 'Proc'
然而,lambdas是一种不同的“味道"。 返回对象时会显示这种细微差别。
proc # returns '#'
lam # returns ''
(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。 如果传递的参数太多而忽略了额外的参数。
- 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
- 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