在 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

相關文章
相關標籤/搜索