ブロックとイテレータ

コンテナ: 1つ以上の他のオブジェクトのリファレンスを保持するオブジェクトのことです。

コードブロック: ブレースまたは do ... end で囲まれたコードのかたまりです。 一般的に、1行のブロックにはブレースを、複数行のブロックには do/end を使います。

例:

{ puts “Hi” } # 1行のブロック
※{...} の優先度が高い
     
do   # 複数行のブロック
※do...end は {...} よりも
結合度が弱くなります。
  ......
......
end  

greet メソッド呼び出しに関連付けをしてみます。

greet { puts “Hi” }

メソッドの引数がある場合、メソッドの直後・ブロックの直前に追加します。

verbose_greet(”Sam”, “dearest hubby”) { puts “Hi” }

自分なりに yield 文でその関連付けを表してみます。(これで良いかどうかちょっと不安ですが・・・)

def verbose_greet (name, relationship)
  yield
puts “#{name}, my #{relationship} ”
end
   
出力結果:
  Hi
Sam, my dearest hubby

yieldが実行されるたびに、ブロック内のコードが呼び出されます。ブロックを抜けると、yield文の直後に制御が戻ります。

yield にパラメータを指定すると、それがブロックに渡されます。ブロック内では、これらのパラメータを受け取るための引数名のリストを縦棒 ( | ) の間に指定します。

def call_block
 yield (”hello”, 3)
end     ↓ ↓
 
call_block{ |str, num| ... }

特定の値までのフィボナッチ数列を出力する簡単な関数を例にします。

def fib_up_to(max)

j1, j2 = 1, 1 # 多重代入 ( j1 = 1 and j2 = 1 )

while j1 <= max


yield j1


j1, j2 = j2, j1+j2

end
end

fib_up_to(1000) { |f| print f, ” ” }
出力結果:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

コードブロックは、イテレータを実装するために使われています。
イテレータ
: 配列などのコレクションから連続する要素を返すメソッドのことです。

animals = %( ant bee cat dog elk ) # 配列を作成する
animals.each { |animal| puts animal } # 配列の要素を繰り返し処理する
出力結果:  

ant
bee
cat
dog
elk
 

その他の例:

[ ‘cat’, ‘dog’, ‘elk’ ].each { |name| print name, ” ” }
cat dog elk
3.times { print “*” }
***
2.upto(5) { |i| print i }
2345
( ‘v’..’z’ ).each { |char| print char }
vwxyz

ブロックはメソッドに値を返すこともできます。ブロック内で最後に評価された式の値が、yieldの値としてメソッドに返されます。(Arrayクラスのfindメソッドはそんな感じです。)

class Array
def find
for i in 0 ... size
value = self[i]
return value if yield(value)
end
return nil
end
end
     
[1, 3, 5, 7, 9].find { |x| x*x > 30 } → 7

その他の例:

[ ‘I’, ‘Q’ ].collect { |x| x.succ } [ ‘J’, ‘R’ ]
[1,3,5,7].inject(0) { |sum, element| sum+element }
16
[1,3,5,7].inject(1) { |prod, element| prod*element }
105
injectを引数なしで呼び出すと、コレクションの先頭要素が初期値として使われ、繰り返しは2番目の要素から開始されます。
[1,3,5,7].inject { |sum, element| sum+element } 16
[1,3,5,7].inject { |prod, element| prod*element } 105

コメント

(必須)

(必須)
(メールアドレスは公開されません)