procとlambdaの違い

初めに

今回はRails開発者が採用面接で聞かれる想定Q&A 53問(翻訳)の中から、procとlambdaの違いについての問いがあり、こちらについて掘り下げていく



前提

 

procとlambdaの共通点

  • procもlambdaも、どちらもブロックをオブジェクト化したものであり、Procクラスのインスタンスである
# proc
proc1 = Proc.new { p "procインスタンス"}
proc1.call 
#=> "procインスタンス"

p "procは#{proc1.class}クラスです"
#=> "procはProcクラスです"
# lambda
lambda1 = lambda { p "lambdaインスタンス" }
lambda1.call
#=> "lambdaインスタンス"

p "lambdaは#{lambda1.class}クラスです"
#=> "lambdaはProcクラスです"


ブロック(block)

  • do ~ endあるいは{}で囲まれたもの
  • ブロック単体で存在することはできない
  • 引数として渡されたブロックはyieldによって実行される



本題(procとlambdaの違い)

 

1. 引数の数

procは想定される引数の数が違っていても、エラーが起きないが、lambdaではエラーが起きる

# proc
proc1 = Proc.new { |a,b,c| p a,b,c}
proc1.call(2,4)

#=>
2
4
nil
# lambda
lambda1 = lambda { |a,b,c| p a,b,c}
lambda1.call(2,4)

#=>
Traceback (most recent call last):
        1: from block.rb:5:in `<main>'
block.rb:4:in `block in <main>': wrong number of arguments (given 2, expected 3) (ArgumentError)

procでは受け取っていない値はnilとなり、エラーは発生していないが、lambdaではエラーが発生していることがわかる


2. ジャンプ構文(return, break)の挙動の違い

procの場合は、returnやbreakが呼び出された場合、呼び出されたメソッドを抜ける挙動になる

# proc
def test_proc
  proc1 = Proc.new { return  p "returnが呼び出されました"}
  proc1.call
  p "処理は終了です"
end

test_proc
#=> "returnが呼び出されました"
# lambda
def test_lambda
  lambda1 = lambda { return p "returnが呼び出されました"}
  lambda1.call
  p "処理は終了です"
end

test_lambda

#=> "returnが呼び出されました"
#=> "処理は終了です"

procは"処理は終了です"の出力がなく、メソッドを抜けていることがわかる



参考

class Proc (Ruby 3.1 リファレンスマニュアル)

Ruby block/proc/lambdaの使いどころ - Qiita