脳汁portal

アメリカ在住(だった)新米エンジニアがその日学んだIT知識を書き綴るブログ

[Ruby] Procとlambdaの違い

ブロックをオブジェクト化する代表的な方法としてProcとlambdaがあるが、その違いに関して簡単に説明

returnに対する挙動の違い

lambda

普通にlambdaから返る(メソッドのreturnと同じ挙動)

def double(lambda_blk)
  lambda_blk.call * 2
end
 
l = lambda{return 10}
puts double(l) # => 20
proc

procが定義されたスコープから戻る

def double(proc_blk)
  proc_blk.call * 2
end

p = proc{return 10}
  # => proc.rb:5:in `block in <main>': unexpected return (LocalJumpError)
puts double(p) # 実行されない
  • TOPレベルで使うと戻り先がなくて例外が発生する

⇒returnを使わなければlambdaと同じ挙動になる

p = proc{10}
double(p) # ==> 20

引数チェックに対する挙動

lambda

引数の数を厳密にチェックする(メソッドの引数チェックと同じ挙動)

l = lambda{|x, y|
  puts "#{x}, #{y}"
}

l.call(10, 20) # => 10, 20 (OK)
l.call(10)  # NG
  # => lambda.rb:10:in `block in <main>': wrong number of arguments (1 for 2) (ArgumentError)
l.call(10, 20, 30) # NG
  # => lambda.rb:10:in `block in <main>': wrong number of arguments (3 for 2) (ArgumentError)
proc

引数の数が合わない場合は調整してくれる

p = proc{|x, y|
  puts "#{x}, #{y}"
}

p.call(10, 20) # => 10, 20 (OK)
l.call(10)     # => 10,    (OK)
  # => yにはnilが格納される
l.call(10)     # => 10, 20 (OK)
  # => 三つ目の引数は無視される

代替記法がそれぞれ違う

lambda

矢印ラムダ

l = ->(x, y){ puts "#{x}, #{y}" }

l.call(10, 20) # => 10, 20 (OK)
  • 試験的にいれてるので今後なくなるかもとのこと
proc

Proc.new

p = Proc.new{|x, y| puts "#{x}, #{y}"}

p.call(10, 20) # => 10, 20 (OK)

最後に

lambdaの方が

  • メソッドに似ている
  • 引数の数に厳しい
  • returnを呼ぶと終了する

のでlambdaの方を使う人が多いらしい(メタプロ曰く)