在-Ruby-中blokproc-和-lambda-有什么区别

29次阅读

共计 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
  1. 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。如果传递的参数太多而忽略了额外的参数。

  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

正文完
 0