天天看點

淺談 Ruby 中的 block, proc, lambda, method object 的差別

當大家在百度中搜尋“block proc lambda”的時候,會出來很多關于這幾個概念之間差別的介紹,既然搜尋結果中已經有了這些介紹,那為什麼還要寫這篇文章?

相信看過百度搜尋結果中排名靠前的幾篇文章的同學,都會發現其實這些文章并沒有很好的說明他們之間差別是什麼,大多隻是介紹各自的用法,加上些許的差別,即使個别介紹了一些差別,也不夠系統,不夠深入。

正是基于上述原因,才醞釀了本文。本文以簡單示例的方式,詳細的介紹了它們之間的差別。相信您閱讀完本文,一定會豁然開朗,并在今後的開發中準确并優雅的使用它們。

由于時間,個人能力水準等有限,本文難免有錯誤或缺失之處,歡迎不吝指出。

block & proc

在介紹它們的差別之前,我們先來看一段有關block的簡單使用方法:

以上介紹了兩種在函數中使用block的方式,第一種是通過yield來使用block,另外一種則是通過block.call來使用block。

proc全稱為procedure,中文翻譯為過程,步驟。關于block和proc的差別,我們先來看一個簡單的示例。

定義一個函數what_am_i并接受一個block,執行體中列印了block的類型,從執行的結果我們看到block的類型為proc,即說明block為proc的一種。

block和proc之間的差別主要有兩個:一是proc可以重複使用,如果某個block将在多個地方被用到,則我們可以将其定義為proc。另外一個差別就是當某個函數需要執行多個閉包的時候,此時我們就無法使用block而隻有使用proc或其他的閉包。

示例如下,在執行某個具體的操作的前後,調用了我們自己的proc。

proc & lambda

關于proc和lambda的差別,我們先來看一個簡單的例子。

上述示例,第一眼看去發覺lambda和proc之間沒什麼差別或者很難發現它們的差別是什麼。

接下來,我們對上述示例做一下簡單的修改,我們将之前的接受兩個參數修改為三個,看看會發生什麼情況。

運作修改後的示例,發現lambda閉包出錯了,出錯的資訊為,錯誤的參數個數。

至此,我們很快就發現了它們之間的一個差別是,lambda會檢查參數的個數,而proc則不會,proc預設将缺失的參數視為nil,并繼續執行代碼,這是為什麼呢?在本節的最後,我們會道出這其中的緣由。

在了解到它們的第一個差別之後,接下來我們再來看一個示例。

這個示例非常的簡單,我們定義了兩個函數proc_return以及lambda_return。這兩個函數一個用proc實作,另外一個用lambda實作,執行體都隻有一行代碼,就是傳回一段字元串。

執行的結果出乎我們的意料,proc并未執行return之後的代碼,而lambda執行了return之後的代碼。

綜上所述,我們得出了proc和lambda的兩個重要差別,一是lambda會進行參數個數的檢查而proc則不會,另外lambda會執行return之後的代碼而proc則不會。

為什麼會出現上述情況,本質的原因在于,proc隻是一段嵌入的代碼片段而lambda則是匿名函數,正因為是匿名函數,是以會檢查函數調用參數,并在函數調用結束之後,繼續執行後面的代碼,而proc由于是嵌入的一段代碼片段,在執行完return語句後,就已經傳回,是以不再執行之後的代碼。

lambda & method object

lambda和method object的用法基本一緻,其唯一的差別在于lambda為匿名函數,而method object為命名函數。

總結

關于block,proc,lambda, method object這四者之間的差別可總結為以下:

block和proc本質上是一段嵌入的代碼塊,并非函數。而lambda和method object都是函數,隻不過lambda是匿名函數,而method object為命名函數。

從本質上了解了它們的差別,我們在今後的開發中就會正确且優雅的運用它們。