在 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,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,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,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,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,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,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 2. 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