Ruby函數lambda知識講解
Ruby語言對于一個剛剛基礎編程語言不久的朋友來說,是一個非常陌生的東西。不過,它的出現可以幫助我們快速簡便的完成一些功能需求。在這里,我們就為大家介紹其中Ruby函數lambda的一些用法。#t#
Ruby的Block塊是它的關鍵特色之一,用塊能夠寫出簡明且高度可重用的算法。即使沒有別的用處,它至少消弱了人們對循環敬畏的態度。這個概念在其他語言和理論中還被稱為:
◆lambda函數
◆匿名函數
◆閉包
這是個十分令人迷惑的詞匯,因為閉包這個詞匯還指對代碼作用域的捕獲。而塊則不需要捕獲這個作用域——例如下面的代碼:
x = lambda {|x,y| x + y}
沒有使用自由變量(沒有綁定的變量;參數列表中正式聲明x和y),因此無須創建一個閉包。
塊在其他語言中有很多種多樣的表現形式,有的簡潔有的冗長。比如對Ruby影響深遠的LISP語言,所使用的塊語法為:
(lambda (arg) "hello world")
對Ruby的設計產生影響的另一種語言Smalltalk,采用方括號來簡潔地表達語法:
[arg| ^"hello world"]
Ruby中,塊的最方便也最常使用的語法是作為函數的參數。它允許簡單地在函數名后面添加一個用do/end 或者花括號{ / }包圍的代碼塊。例如:
5.times {|x| puts x}
這非常的方便,同時也產生了Builder這樣的習慣性用法。Builder可以通過嵌套的塊來很容易地創建分層的數據結構。(提示:就在一月下旬InfoQ即將發表一篇詳細描述如何在Ruby中創建Builder的文章)。
不過,還有一個問題:要傳遞一個以上的塊給函數或方法就沒那么簡單了。它可以實現,但不能用這么短的語法,得使用Proc.new {} 或Ruby函數lambda來創建塊。雖然還不至于恐怖,但這樣會使代碼冗長,而且還引入了一些不受歡迎的詞匯把代碼搞得凌亂不堪。(注意:Proc.new {} 和 lambda {}也有些微妙的不同,但本文不關注它們)。
在特定情況下可能有變通的方法。例如,如果一個API調用需要多個塊,輔助函數就會嵌入到類中,這樣就產生了兩個作用:a) 輔助了塊 b) 帶有貌似命名參數的負作用:
find (predicate {|x,y| x < y}, predicate{|x,y| x > 20})
其中predicate函數僅僅是:
def predicate(&b) b end
它用來返回這個塊。不論這是否合適或者不依賴于特定情況。在這種情況下,下面的代碼——毋庸置疑地——更能表達清楚,也能起到相同的作用。
find (lambda{|x,y| x < y}, lambda {|x,y| x > 20})
為什么呢?因為lambda泄露了實現它的細節——若帶有一個塊參數,就不需要額外的關鍵詞。predicate的解決方案對代碼做了注解,并產生了Ruby函數lambda。需要明確的是,這只是變通的方法。
現在,Ruby 1.9引入了一個新的、更簡潔的語法來創建lambda函數:
x = ->{puts "Hello Lambda"}
新的語法更加簡短,還拋棄了那個不知所云的術語lambda。需要明確的是,這是個語法糖衣。不過它的確有助于寫出可讀性非常好的API代碼。其中一些API可以被稱為“內部DSLs”,盡管它們的定義都很模糊。出于這些,新的Ruby函數lambda定義幫我們擺脫了那個夾在要么是純領域要么是問題確定的代碼中間的晦澀的術語“lambda”。