lambda 和 Proc 幾乎一模一樣,主要差異,差在「檢查參數」和「丟回控制權」
打開 irb console 來試試看下面兩個 method
def test_proc
test = Proc.new { return "Return Successful" }
test.call
"Proc not return"
end
def test_lambda
test = lambda { return "Return Successful" }
test.call
"Lambda not return"
end
我們會發現 lambda 會將控制權丟回呼叫方,繼續執行該方法,而 proc 的 return 則不會,是立即跳出。
test_proc
=> "Return Successful"
test_lambda
=> "Lambda not return"
再來我們嘗試看看檢查參數的差異,分別執行下面兩段程式碼
lambda { |name| puts "Hi, #{name}"}.call
=> ArgumentError (wrong number of arguments (given 0, expected 1))
Proc.new { |name| puts "Hi, #{name}"}.call
=> Hi,
nil
這裡也可以發現 lambda
會對參數進行檢查,如果沒有帶入則會直接拋出 error,但 proc 會直接以 nil 帶入參數。
這也就是為什麼 Rails 中的 ActiveRecord
model 在使用 scope 時,會用 lambda 進行傳遞,原因是相比 proc 來說,更為謹慎
假設我們寫會帶入參數的 scope
scope :with_type, ->(type) { where(type: type) }
你不會希望沒傳值進去他突然變 nil
這樣會有難以 Debug 的情況,假設用 proc 來做的話
當你明確定義參數時,在不傳入的情況下直接呼叫該 scope Product.with_type
結果 SQL query 依舊能夠執行,不會噴錯,因為 proc 會將沒帶入的參數直接設為 nil,在 SQL query 就等同於執行where(type: nil)
我們定義期望參數傳入,在這邊如果不傳入參數,SQL 卻還是能夠進行搜尋,接著就會出現你沒預料到的狀況,這樣是不是有些隱諱?
反而用 lambda 能夠確保參數確實傳遞,如果沒有傳遞,直接拋出 error 告訴你不能這樣做,避免不必要的隱諱查詢。