PerlerのRuby日記

Rubyとか

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