當你們在百度中搜索「block proc lambda」的時候,會出來不少關於這幾個概念之間區別的介紹,既然搜索結果中已經有了這些介紹,那爲何還要寫這篇文章?react
相信看過百度搜索結果中排名靠前的幾篇文章的同窗,都會發現其實這些文章並無很好的說明他們之間區別是什麼,大多隻是介紹各自的用法,加上些許的區別,即便個別介紹了一些區別,也不夠系統,不夠深刻。算法
正是基於上述緣由,才醞釀了本文。本文以簡單示例的方式,詳細的介紹了它們之間的區別。相信您閱讀完本文,必定會豁然開朗,並在從此的開發中準確並優雅的使用它們。編程
因爲時間,我的能力水平等有限,本文不免有錯誤或缺失之處,歡迎不吝指出。ruby
在介紹它們的區別以前,咱們先來看一段有關block的簡單使用方法:閉包
def use_yield yield end use_yield do puts 'use yield' end def use_block_call(&block) block.call end use_block do puts 'use block call' end
以上介紹了兩種在函數中使用block的方式,第一種是經過yield來使用block,另一種則是經過block.call來使用block。函數
proc全稱爲procedure,中文翻譯爲過程,步驟。關於block和proc的區別,咱們先來看一個簡單的示例。spa
def what_am_i(&block) block.class end puts what_am_i {} # =< Proc
定義一個函數what_am_i並接受一個block,執行體中打印了block的類型,從執行的結果咱們看到block的類型爲proc,即說明block爲proc的一種。翻譯
block和proc之間的區別主要有兩個:一是proc能夠重複使用,若是某個block將在多個地方被用到,則咱們能夠將其定義爲proc。另一個區別就是當某個函數須要執行多個閉包的時候,此時咱們就沒法使用block而只有使用proc或其餘的閉包。code
示例以下,在執行某個具體的操做的先後,調用了咱們本身的proc。ip
def action(code) code[:before].call puts 'processing...' code[:after].call end action :before => Proc.new {puts 'before action'}, :after => Proc.new {puts 'after action'}
關於proc和lambda的區別,咱們先來看一個簡單的例子。
def args(code) code.call 'one','two' end args Proc.new { |a,b| puts a,b} args lambda {|a,b| puts a,b}
上述示例,第一眼看去發覺lambda和proc之間沒什麼區別或者很難發現它們的區別是什麼。
接下來,咱們對上述示例作一下簡單的修改,咱們將以前的接受兩個參數修改成三個,看看會發生什麼狀況。
def args(code) code.call 'one','two' end args Proc.new { |a,b,c| puts a,b,c} args lambda {|a,b,c| puts a,b,c} # =< wrong number of arguments (2 for 3) (ArgumentError)
運行修改後的示例,發現lambda閉包出錯了,出錯的信息爲,錯誤的參數個數。
至此,咱們很快就發現了它們之間的一個區別是,lambda會檢查參數的個數,而proc則不會,proc默認將缺失的參數視爲nil,並繼續執行代碼,這是爲何呢?在本節的最後,咱們會道出這其中的原因。
在瞭解到它們的第一個區別以後,接下來咱們再來看一個示例。
def proc_return• Proc.new {return 'Proc.new'}.call puts 'proc_return method finished' end def lambda_return lambda { return 'lambda'}.call puts 'lambda_return method finished' end puts proc_return # =< Proc.new puts lambda_return # =< lambda_return method finished
這個示例很是的簡單,咱們定義了兩個函數proc_return以及lambda_return。這兩個函數一個用proc實現,另一個用lambda實現,執行體都只有一行代碼,就是返回一段字符串。
執行的結果出乎咱們的意料,proc並未執行return以後的代碼,而lambda執行了return以後的代碼。
綜上所述,咱們得出了proc和lambda的兩個重要區別,一是lambda會進行參數個數的檢查而proc則不會,另外lambda會執行return以後的代碼而proc則不會。
爲何會出現上述狀況,本質的緣由在於,proc只是一段嵌入的代碼片斷而lambda則是匿名函數,正由於是匿名函數,因此會檢查函數調用參數,並在函數調用結束以後,繼續執行後面的代碼,而proc因爲是嵌入的一段代碼片斷,在執行完return語句後,就已經返回,因此再也不執行以後的代碼。
def greeting puts 'hello, method object' end method(:greeting).call lambda{puts 'hello, lambda'}.call
lambda和method object的用法基本一致,其惟一的區別在於lambda爲匿名函數,而method object爲命名函數。
關於block,proc,lambda, method object這四者之間的區別可總結爲如下:
block和proc本質上是一段嵌入的代碼塊,並不是函數。而lambda和method object都是函數,只不過lambda是匿名函數,而method object爲命名函數。
從本質上理解了它們的區別,咱們在從此的開發中就會正確且優雅的運用它們。
[1] http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/
無
若是您對算法或編程感興趣,歡迎掃描下方二維碼並關注公衆號「算法與編程之美」,和您一塊兒探索算法和編程的神祕之處,給您不同的解題分析思路。