読者です 読者をやめる 読者になる 読者になる

Rubyのブロックについての理解

qiita.com

実際手を動かすと理解しやすいので、書いてみるのがおすすめ。

基本

def give_me_block
  yield # yieldで暗黙引数のブロックが実行される感じ
end

give_me_block do
  # --- ここから
  p 'Hello, block1'
  p 'Hello, block2'
  p 'Hello, block3'
  # --- ここまでを def give_me_blockに渡す
end
  • do〜endで囲んだところをProcオブジェクトにしてgive_me_blockに渡し、yieldではProcオブジェクトを.callしている

結果

"Hello, block1"
"Hello, block2"
"Hello, block3"

ブロックを受け取るときのルール

  • &をつけることでブロックをうけとることを明示している
  • 引数に渡すことができるブロックはひとつまで
  • 引数のブロックは最後に定義されていないとダメ
  • ブロックはProcのオブジェクト。.callで実行できる
#   def give_me_block_with_param(&block1, &block2) # これはダメ
#   def give_me_block_with_param(&block1, params)  # これはダメ
def give_me_block_with_param(params, &block1)
  p params
  p block1.class
  block1.call
end

引数の渡し方

  • give_me_block_with_param は引数ひとつ(とブロック)なので、そもそもカンマで区切ることはできない
# give_me_block_with_param 123, do #これはダメ
give_me_block_with_param 123 do
  p 'Block1'
end

結果

123
Proc
"Block1"
  • do〜endの代わりに {〜}するときは、どこまでが引数、どこからブロックなのかわからないので括弧をつけてあげる
# give_me_block_with_param 456 { これはダメ
give_me_block_with_param (456) {
  p 'Block2'
}

結果

456
Proc
"Block2"

ブロックをうけとるメリットのひとつは、見た目そのままで後処理など拡張ができること

def sum_and_exec_block(x, y)
  z = x + y
  z = yield z if block_given?
  z
end

p sum_and_exec_block(1, 2)
# 3


# yield zのzがvalueに入ってくる
hoge = sum_and_exec_block(10, 20) do |value|
  value + 10
end
p hoge
# 40

p( sum_and_exec_block(10, 20) { |value| value + 20 })
# 50