Proc.newとlambdaの違い
自分用まとめ。
結論
lambda使っておけば問題ない。
Kernel#procは?
1.8だとlambdaと同じ動きをする。
1.9だとProc.newと同じ動きをする。
使う必要ない。
違いその1
return
lambda内でのreturnは、メソッドのdefと同じ動きをする。分かりやすい。
- lambda
def hoge(code) w = code.call puts "hoge! #{w}" end hoge lambda { return "lambda!" } #=> "hoge! lambda!"
一方Proc内でのreturnは、Procオブジェクト生成時のスコープから抜けようとする。
- Proc.new
def hoge(code) w = code.call puts "hoge! #{w}" end hoge Proc.new { return "Proc!" } #=> hoge.rb:7:in `block in <main>': unexpected return (LocalJumpError)
(トップレベルのmainからreturnはできないのでエラーになる。)
違いその2
引数の数のチェック
lambdaにブロック引数をつけると、その引数の数をつけてlambdaを呼ばないとエラーになる。厳密。
これもメソッドのdefと同じ動きをする。分かりやすい。
- lambda
# OK lambda { |w| "lambda! #{w}" }.call("hoge!") #=> "lambda! hoge!" # NG lambda { |w| "lambda! #{w}" }.call() #=> ArgumentError: wrong number of arguments (0 for 1) lambda { |w| "lambda! #{w}" }.call("hoge!", "fuga!") #=> ArgumentError: wrong number of arguments (2 for 1)
一方Procだと、足りない引数や多すぎる引数は、よしなに計らってくれてしまう。
- Proc.new
# OK Proc.new { |w| "Proc! #{w}" }.call("hoge!") #=> "Proc! hoge!" # OK ## 引数が足りないとnil Proc.new { |w| "Proc! #{w}" }.call() #=> "Proc! " ## 引数が余ると捨てる Proc.new { |w| "Proc! #{w}" }.call("hoge!", "fuga!") #=> "Proc! hoge!"
余談:defとlambdaの違い
スコープ。
"def"はスコープゲートだから出てきたタイミングで新しくスコープが切り替わるけれど、
"lambda"はそのまま。
- def
i = 123 def hoge puts i end hoge() #=> hoge.rb:4:in `hoge': undefined local variable or method `i' for main:Object (NameError)
- lambda
i = 123 lambda { puts i }.call() #=> 123