lambdaとは?
与えられたブロックから手続きオブジェクト (Proc のインスタンス) を生成して返します。Proc.new に近い働きをします。
Ruby 3.1 リファレンスマニュアル
おさらいで、ブロックとはdo~endや{}で囲まれた処理のことを指す。手続きオブジェクトはprocやlambdaによってブロックをオブジェクトにしたもの。
使い方はProc.newとほぼ同じ。Proc.newについてはこちらの記事で。
なぜ作られた?(存在意義)
procを作った後にジャンプ構文(next,break,returnなど)の挙動でprocとは違う挙動をするものが欲しくなったから。予想。
lambdaを使った時と使わない時の違い
lambdaを使わない書き方。帰る方法を増やしたい時に条件文が肥大する。
def back_home(is_fast)
puts "駅に行く"
if is_fast
bullet_train
else
local_train
end
puts "家まで歩く"
end
def bullet_train
puts "終着まで寝る"
puts "16:30分に駅に着く"
end
def local_train
puts "2回乗り換える"
puts "18:00時に駅に着く"
end
back_home(false)
lambdaを使った書き方。if文が必要なくback_homeメソッドがこれ以上大きくならない。手続きオブジェクトを作ることで複数の帰る方法を設定できる。
def back_home(train)
puts "駅に行く"
train.call
puts "家まで歩く"
end
bullet_train = lambda {
puts "終着まで寝る"
puts "16:30分に駅に着く"
}
local_train = lambda {
puts "2回乗り換える"
puts "18:00時に駅に着く"
}
back_home(local_train)
Proc.newとlambdaの違い
引数の扱いが違う
lambda のほうがより厳密です。引数の数が違っていると(メソッドのように)エラーになります。 Proc.new は引数を多重代入に近い扱い方をします。
Ruby 3.1 リファレンスマニュアル
procはブロックと同じ挙動をする。
# procの場合
a = Proc.new {|x,y|
p x,y
}
a.call(1)
#=> 1
#=> nil
# ブロック
[1].map do |x, y|
p n
p i
end
#=> 1
#=> nil
lambdaの方が引数の扱いが厳密でメソッドと同じような扱いになる。
# lambdaの場合
b = lambda {|x,y|
p x,y
}
b.call(1,2,3)
#=> wrong number of arguments (given 3, expected 2) (ArgumentError)
# メソッドの場合
def c(x,y)
p x,y
end
c(1,2,3)
#=> wrong number of arguments (given 3, expected 2) (ArgumentError)
returnとbreakの挙動が違う
return と break は、lambda と Proc.new では挙動が異なります。例えば return を行った場合、lambda では手続きオブジェクト自身を抜けますが、 Proc.new では手続きオブジェクトを囲むメソッドを抜けます。
Ruby 3.1 リファレンスマニュアル
returnとbreakをつけた時の挙動が変わる。
- lambda・・・手続きオブジェクト自体から抜ける
- Proc.new ・・・手続きオブジェクトを囲んでいるメソッドから抜ける
def back_home(train)
puts "駅に行く"
train.call
puts "家まで歩く"
end
bullet_train = lambda {
puts "終着まで寝る"
return puts "16:30分に駅に着く"
}
local_train = Proc.new {
puts "2回乗り換える"
return puts "18:00時に駅に着く"
}
back_home(bullet_train)
#=> 駅に行く
#=> 終着まで寝る
#=> 16:30分に駅に着く
#=> 家まで歩く
back_home(local_train)
#=> 駅に行く
#=> 2回乗り換える
#=> 18:00分に駅に着く
まとめ
lambda・・returnやbreakを使っても手続きオブジェクトを囲んでいるメソッドから抜けない。だからブロック内での処理を抜けたいがメソッドからは抜けたくない時に使える。
proc・・returnやbreakを使うと手続きオブジェクトを囲んでいるメソッドから抜ける。だからブロック内での処理結果によってメソッドごと抜けたい時に使える。
引数を厳密に扱いたい場合はlambdaがおすすめ。