【Ruby】Block, Proc, Lambdaの違い
BlockもProcもLambda も同じようなことができるけど、違いは?
と疑問に思ったので、下記を参考にまとめ。(英語の勉強も兼ねて、、、今回の記事ではわかりやすさのため、多少意訳して紹介します)
Block、Proc、Lambdaの使い方の例は下記が参考になれば。(メソッドに渡す使い方のみ限定で紹介)
【BlockとProcの違い】
1. Procはオブジェクト、Blockはオブジェクトじゃない
例えば、Procは代入できる
p = Proc.new { puts "Hello World" }
a = p
Blockはできない
a = { puts "Hello World"}
=>
(repl):1: syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '('
a = { puts "Hello World"}
^
(repl):1: syntax error, unexpected '}', expecting end-of-input
a = { puts "Hello World"}
2. ブロックはメソッドの引数に1つしか指定できない。
def greeting(&block1, &block2)
block1.call
block2.call
end
greeting {puts "Hello"}, {puts "Konnichiwa"}
=>
(repl):1: syntax error, unexpected ',', expecting ')'
def greeting(&block1, &block2)
proc なら引数として、メソッドに複数指定できる
def greeting(proc1, proc2)
proc1.call
proc2.call
enda = Proc.new{puts "Hello"}
b = Proc.new{puts "Konnichiwa"}
greeting a,b
=>
Hello
Konnichiwa
【LambdaとProcの違い】
実はどちらもProcオブジェクト
proc = Proc.new { puts "Hello world" }
lam = lambda { puts "Hello World" }proc.class # returns 'Proc'
lam.class # returns 'Proc'
でも、戻り値を見ると、ちょっと違う値を返す
proc # returns '#<Proc:0x007f96b1032d30@(irb):75>'
lam # returns '<Proc:0x007f96b1b41938@(irb):76 (lambda)>'
めっっちゃLambdaとProcは似てるし、どっちもProcクラスのインスタンスだけど、
下記に主な違いを紹介します
1. Lambda は引数の数が合っていないとNG。Procは大丈夫
# 引数1つのlambda 作る
lam = lambda { |x| puts x }
#2 が出力される
lam.call(2)
#下記二つはArgumentError発生
lam.call
lam.call(1,2,3)
#引数1つのProc 作る
proc = Proc.new { |x| puts x }
#2 が出力される
proc.call(2)
# returns nil
proc.call
#1 が出力される(第二&第三引数は無視される)
proc.call(1,2,3)
2. 戻り値が微妙に違う
Lambda内戻り値は、Lambda のすぐ外(下記ならLambda_test メソッド)の戻り値となる(Lambda内のreturnがLambda のすぐ外のコード(Lambda_test メソッド)を実行するため)
def lambda_test
lam = lambda { return puts "lambda"}
lam.call
puts "Hello world"
endlambda_test
=>
lambda
Hello world
Proc内戻り値は、Proc の戻り値となる。(Proc内のreturn が、callが実行された場所のメソッドを実行するため)
def proc_test
proc = Proc.new { return puts "proc"}
proc.call
puts "Hello world"
endproc_test
=>
Proc
【Closureについて】
メソッド内でProcを使用(メソッド内のローカル変数を、そのProcで参照)すると、参照されたローカル変数が保存される
def counter
n = 0
return Proc.new { n+= 1 }
end
a = counter
a.call # returns 1
a.call # returns 2
b = counter
b.call # returns 1a.call # returns 3
上記を見ると、counterメソッド内のローカル変数n が保存されているのがわかります。
例えとして、「Procとグループ化されているメソッドは、スーツケースみたいに、開封(実行)した時に、スーツケースを詰めた時に入れたものが保存されている」
【トリビアについて】
1. Lambdaと無名関数
ラムダって数学用語だよね??って思った方もいるのでは。
例えばf(x)=x+5を ラムダ式で書くと、λx. x+5 みたいなやつ。
プログラミングだと、匿名関数、無名関数と呼ばれる物をlambda と呼ぶ。(javascriptとか、Ruby以外の言語でも。)
#普通のメソッド。名前(sqsum)がある
sqsum(x,y) = x*x + y*y
#無名関数。ラムダ。
(x,y) -> x*x + y*y
2. んじゃ、procはどこから来たの??
ProcはProcedure(手続き)の略。特定のタスクをするために、パッケージ化された一連の命令。
他の言語では関数、ルーチン、メソッド、または呼び出し可能ユニットなどと呼ばれる!(普通は何回も実行される可能性のあるタスクをProc化する)
以上ですーーー!!
今回の記事はトリビアとかも挟んであって、読んでて楽しかった。
Adamさんっていう方が書いてたぽい。こういう、興味を沸かせる説明ができるDeveloperさんになりたい、、
おやすみなさいいいぃぃぃ