QA@IT

RubyでlambdaとProcの違いは?

7157 PV
sqr = lambda {|x| x ** 2 }
puts sqr.call(3) # => 9
puts sqr[3] # => 9

sqr = Proc.new {|x| x ** 2}
puts sqr.call(3) # => 9
puts sqr[3] # => 9

と、RubyのlambdaとProcは同じように見えますが、何か違いがあるのでしょうか?

回答

lambda と Proc は、どちらも Proc オブジェクトということでは同じですが、挙動が違います。
lambda で作成した Proc オブジェクトは、よりメソッドと近い挙動をします。

まずは、引数の取り扱いです。Proc.new で作成した Proc オブジェクトでは、引数の数があっていなくても実行されますが、lambda で作成した Proc オブジェクトでは ArgumentError となります。

proc_obj = Proc.new {|x, y| [x, y] } #=> #<Proc:0x007ff96a8c8fc8@(irb):1> 
lambda_obj = lambda {|x, y| [x, y] } #=> #<Proc:0x007ff96a8d0d18@(irb):2 (lambda)> 

proc_obj.(1) #=> [1, nil] 
lambda_obj.(1)
#=> ArgumentError: wrong number of arguments (1 for 2)

次に、Proc オブジェクトのブロック内で return, break したときの挙動が違います。Proc.new で作成した Proc オブジェクトの中で return した場合は、Proc オブジェクトを call したコンテキストで return しようとします。そのためトップレベルで call した場合、LocalJumpError となります。

# トップレベルで実行した場合
proc { return 1 }.call #=> LocalJumpError: unexpected return

# メソッド内で実行した場合
def foo
  proc { return 1 }.call
  return 2
end

foo #=> 1

一方、lambda で作成した Proc オブジェクトは、メソッド内で return したときと同様でそのブロック内の処理を抜けるのでトップレベルで実行してもエラーとなりません。

lambda { return 1 }.call #=> 1 

また、Procオブジェクトを作成するには、Proc.new や lambda を使う以外にも、Kernel#porc メソッドを使う方法があります。Kernel#proc で作成した Proc オブジェクトは Proc.new で作成した Proc オブジェクトと同様の挙動をします。

余談になりますが、Proc オブジェクトが Proc.new で作成されたのか lambda で作成されたかを確認するためのメソッドとして、Proc#lambda? メソッドが用意されています。

lambda {}.lambda? #=> true 
proc {}.lambda? #=> false 

詳しくは、lambda と proc と Proc.new とイテレータの違い を見てください。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。