2012年7月7日土曜日

[Scala] 値を返すFor文

久々にScala。
前回はフィルタ条件付きのFor文を見たので、今回は値を返すFor文を見てみる。

    val a : Array[Int] = Array(-1, 2, -3);
    val result : Array[Int] = for (i: Int <- a) yield i.abs;
    for (i <- result) print(i);

yield節をつけることでこのfor文は結果を返すようになる。yieldの後ろがブロック式(複文)の場合には最後の 文 が返る(ブロック式の値は最後の文の値になるのがScalaのルール).

実行結果:
123


Arrayの関数呼び出しを使って書く場合は Traversable#map を使う。
    val result2: Array[Int] = a.map((i : Int) => i.abs);
    for (i <- result2) print(i); 

実行結果:
123

省略して書くとこんな感じ。
    val result3 = a.map(_.abs);

例によって、独自クラスでfor yieldを使えるようにしてみる。

object ForYieldSample {
  def main(args: Array[String]) {
    val a : Array[Int] = Array(-1, 2, -3);
    val fey : ForEachYieldable[Int, Array[Int]] = new ForEachYieldable(a);
    val result : Array[Int] = for (i: Int <- fey) yield i.abs;
    for (i <- result) print(i);
  }
}

class ForEachYieldable [A, Repr <: Array[A] ](col: Repr) {
  def repr: Repr = col;
  def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
    println("Here is ForEachYieldable#map");
    val b = bf(repr)
    b.sizeHint(repr)
    for (x <- repr) b += f(x)
    b.result
  }
}
実行結果:
Here is ForEachYieldable#map
123

確かに ForEachYieldable#map が実行されている。
元の TraversableLike#map の実装では、
val b = bf(this)
b.sizeHint(this)
となっていたのだが、この ForEachYieldable 自身は Traversable を実装していないので、 実際のデータを保持しているrepr を引数に使っている。このように、map自体の実装で使わなければ ForEachYieldable 自身に foreach を実装する必要はない。

0 件のコメント:

コメントを投稿