rubyを扱っていると、当たり前のようにdo ~ end
の記述を書きますが、実際にはどんな感じで実行されているのか、サラッと書きます。
厳密な話は置いておきましょうよ😚
ノリで理解してくれればok!
block/procを理解する
Ruby block/proc/lambdaの使いどころ
こちらの記事が凄いわかりやすいので、細かいことは読んでほしいのですが、
簡単な理解を箇条書きします。
- blockは処理の集合
- blockは単体で存在しない、引数になる
- blockはメソッドの最後の引数になる(do~endは2つない)
-
&block
はblock
をproc
に変換してる - procはblockをオブジェクトにしたもの
細けえことはコード見ればええねん🖐
blockの実行方法
ここで注意してほしいのは、
実行しているのはjust_do_your_block!
メソッドで、その引数にblock
を渡しているだけです!
つまりreturn
されるのはjust_do_your_block!
の最後の値であって、
今回はたまたまblock.call
の返却値がそのまま出力されているだけです🤽♂️
class_for_test.rb
# クラス定義
class ClassForTest
def just_do_your_block!(&block)
block.call
# instance_eval(&block) # でもok
# yield # でもok
end
end
# 実行部分
ClassForTest.new.just_do_your_block! do
'Hello ruby!'
end
# => "Hello ruby!"
ブロック変数と一緒に実行する
blockが最後の引数になってるということがわかりやすいですね。
class_for_test.rb
class ClassForTest
def just_do_your_block!(e, &block)
block.call(e)
# instance_exec(e, &block) # でもok
# yield(e) # でもok
end
end
ClassForTest.new.just_do_your_block!('block_params') do |e|
puts "Hello ruby! with #{e}"
end
# => "Hello ruby! with block_params"
mapを実装してみる
実際のコードはもっと複雑そうだし、C言語はよくわかりません🙄
単純に出力結果をadd
しているだけですね
array_for_test.rb
# クラス定義
class ArrayForMap
def initialize(array)
@array = array
end
def map(&block)
new_array = []
@array.each do |e|
new_array << block.call(e)
end
new_array
end
end
# 実行部分
array = ArrayForMap.new([1,2,3])
array.map do |e|
e + 1
end
# => [2, 3, 4]
所感
block/proc
という概念は、ちゃんと考えると理解できますが、無意識でも使えるのがruby
の凄いところなのかもなあ、と思いました。
てか、他の言語にもblock/proc
ってあるのだろうか🌝🌚