共计 3202 个字符,预计需要花费 9 分钟才能阅读完成。
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 '#<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
- 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 '#<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。如果传递的参数太多而忽略了额外的参数。
- 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