# 3. イテレータ

- 3.1 イテレータとは何ですか
- 3.2 イテレータにブロックを渡すにはどうすればいいですか
- 3.3 ブロックは呼び出したメソッドの中からどのように使われますか
- 3.4 `Proc.new`では手続きオブジェクトが作られませんが

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

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

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

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

    data = [1, 2, 3]
    data.each do |i|
      print i, "\n"
    end

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

    $ ruby test.rb
    1
    2
    3

つまり`do`と`end`で囲まれたブロックが配列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 イテレータにブロックを渡すにはどうすればいいですか

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

## 3.3 ブロックは呼び出したメソッドの中からどのように使われますか

メソッドの中からブロックを使用するには、`yield`制御構造、ブロック引数、 `Proc.new`の3種類の方法で行うことができます。( Cで書かれた拡張ライブラリ の中では、`rb_yield`が使われます。)

`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.4 `Proc.new`では手続きオブジェクトが作られませんが

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

link: [FAQ::イテレータ]
reverse link: [Ruby FAQ]