由上圖可以知道Proc跟lambda是同一個類別,Proc跟lambda是Ruby很常見的語法,它們的概念非常相似,也有很多值得探討的地方。
參考文章
這是我看到講述 Proc / Lambda / Block 最好的文章之一。
Block 無法獨立存在
在Ruby程式語言,Block 不是物件不能單獨存在,Ruby 有內建兩個方法使 Block 物件化且單獨存在:Proc 和 Lambda。
如何讓 Proc / Lambda 獨立存在:使用Block
Proc 可以將 Ruby 的程式碼保存起來,並且在需要的時候再執行它,或當作 Block 傳入其他函數。在 Proc.new
後面接一個 Block 就可以產生一個 Proc 的物件,物件化後就是一個參數,接著可以使用 call
方法來執行 Block 內的程式碼。
下面為各種使用call
的方式:
我們拿JS來做比喻好了。以下圖來說,我們了解到a, b, c 在 javascript 的世界中扮演的角色為lambda,lambda指的是匿名函數(Anonymous Function)。當function call相當於lambda直接被執行,跟function後面直接加上括號的意思是一樣的(Immediately Invoked Function Expression, or IIFE)。
Proc / Lambda return
上述這篇很詳細的講到Lambda與Proc的差別。但總之個人認為比起Lambda,Proc的雷非常多,像是 Proc 如果寫了 return 之後就不會繼續執行了。
def test_proc
puts 'start'
hi_proc = Proc.new { return 'Stop here.'}
hi_proc.call # 止於該行
puts 'end' # 該段就不會執行
end
若為lambda的話就不會遇到這種問題,return完後還可以繼續執行。舉第1個例子(源自:這篇):
def test_return(callable_object)
callable_object.call * 5
end
la = lambda { return 10 } # 也可寫成 la = ->{ return 10 }
pr = proc { return 10 } # 也可寫成 pr = Proc.new { return 10 }
puts test_return(la) # 50
puts test_return(pr) # 顯示 LocalJumpError 錯誤訊息
第2個例子(源自:這篇):
def test_proc
pr = Proc.new { return 10 }
result = pr.call
return result * 5
end
def test_lambda
la = lambda { return 10 }
result = la.call
return result * 5
end
puts test_proc # 10
puts test_lambda # 50
嚴謹的 Lambda
由上例我們可以知道,當正常的呼叫他們值都一樣,但例2跟例3我們可以發現,當例2沒有給值的時候ruby會預設給它nil(不嚴謹),例3則會噴錯。Proc.new
在model scope使用上比較不適合,尤其是當如果model發生問題而要debug的話真的有可能會找到瘋掉,反之lambda在不符合格式的狀況,會跳出Error,顯然Proc和lambda在這邊就有很大的差別。
What is &
&在ruby的本質是傳遞block用。由上例我們將 {1+1}的block傳遞進去,而這種寫法跟以下寫法一樣:
由上述例子,我們可以解讀成(&block)進去block裡面會轉成proc並且直接執行。那其實上面的寫法也可以在其他地方再執行,例如寫成以下的形式:
下例yield的例子印出的結果和上面一樣,我們可以得出一個結論:yield只是把(&block)的寫法再簡化
看完上面的講解再看下面的例子就不會那麼難懂了。square在這裡是一個Proc,那在block裡面執行(也就是call)的寫法跟(&block)的寫法如出一徹。
下面這種寫法意思也跟上面一樣,只不過主角從proc變成methods
to_proc
Some methods take a block, and this pattern frequently appears for a block — StackOverflow
:foo.to_proc # => ->x{x.foo}
to_proc的用法可以看我寫的另外一篇文章:
其他語法
介紹一下Ruby 的很像 Promise的寫法,但不是Promise(這是我們前端教的):
下面這篇連結也介紹了Proc composition的用法 🤣
參考資料: