前のページ 次のページ 目次

3. イテレータ

3.1 イテレータとは何ですか

ブロックや手続きオブジェクトを活用するメソッドをイテレータと呼びます.

イテレータは制御構造(特にループ)の抽象化のために用いられるメソッド の一種です.

といってもよくわかりませんね.実際の例を見た方が早いかもしれません.イ テレータはコレクションの各要素に対して同じ処理を繰り返したいような場合 によく使われます.例えばこんな感じです.

data = [1, 2, 3]
data.each do |i|
  print i, "\n"
end
このコードの出力はこのようになります.

$ ruby test.rb
1
2
3
つまりdoendで囲まれたブロックが配列dataの各要素に対して繰 り返されるわけです.

これをCで書くと次のようになります.

int data[3] = {1, 2, 3};
int i;
for (i = 0; i < 3; i++) {
  printf("%d\n", data[i]);
}
このようにforを使って書く場合,境界条件の判定ミスでバグが生まれる 可能性がありますが(こんな単純な場合なら大丈夫でしょうが),イテレータを 使えばそのような心配はありませんね:-)

また,do...endの代わりに{...}を使うこともできます.

data = [1, 2, 3]
data.each { |i|
  print i, "\n"
}
このコードは先の例と全く同じ動作をします.ただし,do...end{...}で動作が異なる場合があります.

foobar a, b do .. end # foobar がイテレータとして呼び出されます
foobar a, b { .. }    # b がイテレータとして呼び出されます
これは{ }の方がdoブロックよりも結合強度が強いためです.

イテレータにブロックを渡すには,メソッドの後ろにブロックを置く 方法の他に,手続きオブジェクト(を 指す変数,定数)の前に&をつけて引数として渡す方法があります.

3.2 ブロックはイテレータの中でどのように使われますか

メソッドの中からブロックを実行するには,yield制御構造,ブロック引数, Proc.newの3種類の方法で行うことができます.

yieldの場合には,yieldの後ろに続く引数が,ブロックパラメータと してブロックに渡され,ブロックが実行されます.

ブロック引数は,メソッド定義の引数の最後に&methodという形で置かれ, メソッドの中で,method.call(args...)という形で呼ばれます.

Proc.newは,メソッドの中で使われたときには,引数としてそのメソッドに 渡されたブロックをとり,そのブロックを内容とする手続きオブジェクトを 生成します.procまたはlamdaも同様です.

def a (&b)
  yield
  b.call
  Proc.new.call
  proc.call
  lambda.call
end
a{print "test\n"}

3.3 &がついた引数は何ですか

手続きオブジェクトをブロックとして受け渡しするための引数です. 引数列の一番最後に置きます.

3.4 ブロックに引数を渡すにはどうしますか

ブロックの先頭に,仮引数を||で囲って置くと,実引数が多重代入されます.

3.5 Proc.newでは手続きオブジェクトが作られませんが

Proc.newは,ブロックを与えられないと手続きオブジェクトを生成できず, エラーになります.メソッド定義の中で 使われるブロックなしのProc.newは,メソッド呼出しにブロックが与えられて いることを仮定しています.


前のページ 次のページ 目次