RubyのブロックとProc
こんばんは。ろんです。最近は冷え込みますね…
暖房器具はオイルヒーター派です。
今日はRubyの強力なお友達、ブロックについて紹介します。
並列してるProcとはブロックをオブジェクト化したもので、まずはブロックの理解から初めてこうと思います。
Rubyのブロックとは?何に使えるものなのか
私の解釈では、参照する事ができて、メンバの更新が可能なメソッドの事。
Javaでいう参照渡しが可能な関数の事を指すようです。
引用先のページではモジュールパターンのような応用が可能とありますが、私はこれを
observer patternと解釈しました。
かろてんさんのデザインパターンの説明がわかりやすいので、ぜひ読んでみてください。エモいという言葉は好きではないですが、マジでエモかった…(褒め言葉)
モジュールパターンについての説明は結城浩さんのデザパタ本が個人的におすすめです。ちょっとヒく厚さなんですが、1週間に1章とかでもいいので読んでおくと設計系の話を見かけた時に抵抗なく入れるし、何より説明が具体的でわかりやすいですよ。
物に例えるところがイメージしやすくていいですよね…
それでRubyのブロックとはなんなのか
だいぶ話が私の設計思想に傾いてしまいましたが、文脈を戻してブロックの説明です。
そう、ブロックはcontext(文脈)が大事なのですよ!!
def block_sample arg
arg + yield
end
p block_sample 3 { 2 }
block_sampleの返り値は何になると思いますか?
正解は5です。
argについての説明は割愛しますが、yieldはブロックの処理結果を呼び出しているメソッドです。
あっけない感じがしますね?しかし、このブロックにはちょっとしたクセがあります。
- ブロックで宣言した変数は外部から参照することができない( 束縛 )
- 他のメンバの代入に影響を及ぼす
ブロック評価の順番とローカル変数への影響
def return_calculate_add val1, val2
val1 + yield(5 + val2)
end
p return_calculate_add(3, 4){|x + y| x + y }
これで下記のうちどの値が返ってくるでしょう?
1. 9 2. 12 3. 15
正解は2の12です。
まずval1, val2それぞれに代入されて
def return_calculate_add val1, val2
val1 + yield(5 + val2) # val1=3, val2=4
end
次にブロックの評価がされます。
return_calculate_add(3, 4){|x + y| x + y } # x=5, y=4
最後にメソッドの中に戻ってval1と足し算してあげれば完了です。
こちらはどうでしょうか?
def return_calculate_add val1, val2
val1 + yield(5 + val2)
end
x = 10
p return_calculate_add(3, 4){|x + y| x + y }
惑わされないでくださいね。スコープの外に定義されている変数なのでブロックでは参照されません。答えは同じです。
def return_calculate_add val1, val2
val1 + yield(5 + val2)
end
x = 10
p return_calculate_add(x, 4){|x + y| x+= x + y }
答えは19です。
def return_calculate_add(val1, val2)
val1 + yield(val2, 5)
end
z = 10
p return_calculate_add(z, 4){|x, y| z+= x + y }
p z
問題はこれで最後です。*1に答えを記載しましたのでチャレンジしてみてください。
これが正解出来たら今日の晩ご飯にデザートをつけてもいいと思います。
応用できそうなこと
共有スコープを使いたい時に便利そうですよ。
よくインスタンス変数にお世話になっていますが、こんなメソッドの書き方ができそうです。
# ケーキの数を計算してくれるメソッド
def cakes_calc cakes, &const
p plain_text = "カップケーキが#{cakes + const.call}個"
end
sample_constructor = Proc.new {
result, pledged_cakes = 0, [3, 8, 1]
bought_cakes, made_cakes = 0
bought_cakes = 1000 / 120
made_cakes = 1
pledged_cakes.each do |c|
result += c
if c == pledged_cakes.last
result += bought_cakes + made_cakes
end
end
result
}
cakes_calc(12, &sample_constructor) # => "カップケーキが33個"
ブロック内ではスコープ外に参照を置いていませんが、もちろん参照は可能です。
これならメンバが再代入される危機も薄れて一石二鳥!
うーん。命名がビミョー。
本日は作り置きのハンバーグを食べ損ねたので、美味しい肉バルの紹介です。
虎ノ門界隈にしてはランチのコスパが~1500円程度とお手頃です。
赤身は臭みがなくて程よく柔らかく、ジューシーなのでわさび醤油ソースでいただけるランチメニューがおすすめ。
同僚の方が食べていたグラタンにonされているハンバーグも私の拳くらいあるのでした。また行きたい。
引用・参考 :
( ありがとうございます )
答えは29, 19
*1:こちら