前回はフィルタ条件付きの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 件のコメント:
コメントを投稿