Ruby の yeild を理解してみる
例題
module Enumerable def sum if block_given? # @see http://www.ruby-lang.org/ja/man/html/Enumerable.html#inject inject(0) {|result, value| result + yield(value) } else inject(:+) end end end ary = [1, 5, 3] # ブロックを追加しない場合 # 総和 p ary.sum # => 9 # ブロックを追加した場合 # 二乗和 p ary.sum {|x| x * x} # => 35 # 下記のように書き直せる # ary.sum do |x| # x * x # => 35 # end
ary.sum の場合
- ary.sum にはブロックが渡されていない
- sum メソッドでブロックが渡されているかどうかの判定 if block_given? で偽になる
- inject(:+) で ary[1, 5, 3]が加算される
(1 + 5 + 3 = 9)
ary.sum {|x| x * x} の場合
- ary.sum に {|x| x * x} ブロックが渡されているので、if block_given? で真になる
- inject(0) { ... } で ary 配列の 0番目から処理が始まる
- inject(0) { ... } ブロックに 1 が value に代入されて、yeild に引数として渡される
- yeild に渡された後、{|x| x * x} ブロックに渡されて、二乗される
(1 * 1 = 1) - 二乗された値は、inject(0) { ... } ブロックに戻り、result に代入される
(result = 1) - 次の配列の値 5 が value に代入された後に、yield を経て {|x| x * x} で二乗される
(5 * 5 = 25) - そして二乗された値は、value と合算される
(value = value + 25 = 26) - 6. からの処理と同様に配列の値 3 が渡され、同様の処理を得て、二乗和の 36 になる
(value = value + 9 = 36)
簡単なまとめ
- yield はブロック呼び出しに使います。
⇒ yield を定義したメソッドの後に記述されたブロックを呼び出す。 - yield はブロックを評価した結果を返します。
⇒ 例文の場合、{|x| x * x} ブロック内で x * x を計算した結果を yield が戻り値として返す。 - ブロックの評価結果を使用するタイプです。
⇒ メソッド sum 内で yield に渡された引数は {|x| x * x} ブロックで処理され、その戻り値を引き続き sum メソッド内で処理を行う。 - 繰り返し処理が複数回ある場合、yield を利用することでブロックを入れ子にする必要がなくなり、メソッドチェインとして記述できるようになるメリットがある。