昨天解謎解到一半,發現區塊的類別是Proc。啥?什麼是Proc?其實昨天提到的區塊,實際上它並不是物件!不能直接像物件那樣被操作。
所以該如何操作區塊呢?今天就來談談這個部分。先來看看書中一段:『我們可以建立一個代表區塊的物件,依據物件建立方式的不同,它可以被稱為一個proc或一個lambda。proc的行為如同區塊,而lambda的行為如同方法。然而,他們都是Proc類別的實例。』(p.198)
※ proc與lambda
1. 建立proc
(1)第一種建立proc的方式:透過調用方法來建立proc
def makeproc(&iamproc)
iamproc
end
上面的方法看起來就像昨天區塊引數的介紹,當我們在引數前綴一個『&』時,我們已經將所伴隨的區塊轉換成一個Proc物件並存入iamproc中,另外在方法中再傳回Proc物件。
此時我們可以利用makeproc這個方法來建立Proc物件:
aa = makeproc{|x| x*x}
=> #<Proc:0x007fe6a5929cb0@(irb):43>
bb = makeproc{|x| x+x}
=> #<Proc:0x007fe6a59b8730@(irb):44>
所有的Proc物件都具有call這個方法,當它被調用時,會執行區塊中的程式碼:
aa.call(5)
=> 25
bb.call(3)
=> 6
(2)Proc.new
aa = Proc.new{|x| x*x}
=> #<Proc:0x007fcb1d239de0@(irb):1>
這個建立Proc實體的方式,是所有方式中最明顯的,其實下面這兩種寫法是完全等效的,大家可以比較看看:
def test(&block)
block.call
end
與
def test
Proc.new.call
end
(3)Kernel.lambda
bb = lambda{|x| x+x}
=> #<Proc:0x007fcb1e0b52c0@(irb):2 (lambda)>
bb.call(3)
=> 6
在文章一開始,有節錄書中一段話,指出Proc類別下有proc與lambda之分別,剛剛前兩種建立Proc物件的方法都是建立出Proc下的proc,而第三種則很明顯,是建立出Proc下的lambda,至於proc與lambda到底差在哪裡,我們隨後介紹完建立方法會解釋。
(4)Kernel.proc
這裡所指的proc與上面的lambda都屬於Kernel模組的方法,他們都是全域方法。
cc = proc{|x| x+x}
=> #<Proc:0x007fcb1c017f18@(irb):5>
cc.call(5)
=> 10
Ruby1.8以前proc都只是lambda的同義字,不過Ruby1.9之後,proc其實是Proc.new的縮寫。
2. 調用proc或lambda
除了call這個方法可以傳遞引數給區塊之外,也可使用中括號:
cc = proc{|x,y| x+y}
cc[4,9]
=> 13
dd = lambda{|x,y| x*y}
dd[7,8]
=> 56
3. lambda與proc有何差別
『proc是一個區塊的物件形式,行為就如同一個區塊;lambda的行為稍有不同,叫像一個方法而非區塊。』(p.203)
dd.proc?
NoMethodError: undefined method `proc?' for #<Proc:0x007fcb1cbe1f88@(irb):8 (lambda)>
dd.lambda?
=> true
上方所示,lambda?因為如同一個方法,我們可以用來確定Proc物件是不是proc或lambda,但我們只有lambda?而不會有proc?這個方法。
另外也有人說lamnda就是比較嚴謹的proc,傳入的參數不足,是會噴錯的,例如:
aa = proc{|x,y| puts x ; puts y}
=> #<Proc:0x007fb3c4ae21d8@(irb):1>
bb = lambda{|x,y| puts x ; puts y}
=> #<Proc:0x007fb3c330f8f8@(irb):2 (lambda)>
aa[3,4]
3
4
bb[3,4]
3
4
aa[3]
3
bb[3]
ArgumentError: wrong number of arguments (1 for 2)
其實寫到這裡,對於proc和lambda實作性還是不太清楚,有關proc與lambda之間的內容,網路上也有很多人做過分析,大家有興趣也可以多看看:
Ruby Block, Proc and Lambda
Ruby Gossip: 程式區塊與 Proc
[Ruby] Block & Proc/Lambda
Ruby的block, lambda, Proc與函式物件
=================================================
29天!
“It is never too late to be what you might have been.” George Eliot
只要開始,永遠不嫌晚,快加入Ruby的行列吧XD