Ruby

【Ruby】yield の役割

自分は yield をなかなか覚えられないでいます。分かったと思ったら、また忘れて考えています。もう一度理解した今、もう一度記事として書いておこうと思います。この事でつまづいている人の参考になれば幸いです。

まず yield とはどんな意味があるのか気になりました。きっと英単語に由来しているはずだろうと考え、大辞林で調べました。その意味はいくつかあるようです。

  • 生み出す・もたらす
  • 譲る・与える
  • 屈する・負ける
  • 取って代わられる

これらすべての言葉を使って説明できることに気づきましたので、まずサンプルとしてコードを書きます。

# yield を内包するメソッドを定義
def yield_mean?
  # ブロックを渡したのなら返す
  if block_given?
    yield( "Given Block. Example Code." )
  else
  # ブロックを渡さなかったのなら返す
    "Not Given Block."
  end
end

# ブロック付きで呼び出し
yield_mean? do | item |
  # このブロックが yield を評価する
  p item
end


# ブロックはないので yield は評価されない
p yield_mean?

このコードの出力結果は以下のようになります。

"Given Block. Example Code."
"Not Given Block."

yield_mean? を呼び出した時に使用したブロックパラメーターは、このメソッド内部に記述された yield の引数を示していることが分かります。この一連の流れはまさに大辞林で書かれていた意味と重なります。Ruby ではすべてがオブジェクトでしたね。ブロックさえもオブジェクトなのです。

yield はブロックにメソッド内部の式をもたらす・与える」「ブロックはそのメソッドのレシーバや引数からの流れ屈する形でメソッド内部の yield へつながる」「ブロックはそのメソッド内部の yield に取って代わられる」

この表現がすべて正しいのかは分かりませんが、このような感じではないかと考えています。

ブロックパラメーターの数が yield の引数よりも多かった場合には、その分だけ nil が得られます。逆に少ない場合は、単に呼び出されません。

def test_yield
  # 引数なしで全て nil
  yield
  # 多ければその数だけ nil
  yield(1)
  # 多ければその数だけ nil
  yield(1, 2)
end

puts "- a 引数ひとつ -"
test_yield do | a | p [a] end

puts "- a, b, c 引数みっつ -"
test_yield do | a, b, c | p [a, b, c] end

puts "- *a 引数を展開 -"
test_yield do | a, b | p [*a, *b] end

以下が yield から得られたオブジェクトを配列で見やすくまとめた出力の結果になります。

- a 引数ひとつ -
[nil]
[1]
[1]
- a, b, c 引数みっつ -
[nil, nil, nil]
[1, nil, nil]
[1, 2, nil]
- *a 引数を展開 -
[[]]
[[1]]
[[1, 2]]