tapitapi’s blog

1日1杯タピオカ!エンジニア

【Ruby】Block, Proc, Lambdaの違い

BlockもProcもLambda も同じようなことができるけど、違いは?

と疑問に思ったので、下記を参考にまとめ。(英語の勉強も兼ねて、、、今回の記事ではわかりやすさのため、多少意訳して紹介します)

blog.awaxman.com


 

Block、Proc、Lambdaの使い方の例は下記が参考になれば。(メソッドに渡す使い方のみ限定で紹介)

tapitapi.hatenadiary.com

 

【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
end

a = 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"
end

lambda_test

 

=>

lambda
Hello world

 

Proc内戻り値は、Proc の戻り値となる。(Proc内のreturn が、callが実行された場所のメソッドを実行するため)

 

def proc_test
proc = Proc.new { return puts "proc"}
proc.call
puts "Hello world"
end

proc_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 1

a.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さんになりたい、、

twitter.com

 

おやすみなさいいいぃぃぃ