for式はforeach
社内の勉強会で
for式はforeachに展開される。
なので、自前のクラスでもforeachを実装すれば、for式で回せる。
っていう話をしたので、実証してみる。
まずは「for式がforeachに展開される」ことを確認。
package sample1
object Main extends App {
val seq = Seq(1, 2, 3)
for (i <- seq) println(i)
}
コンパイル時に-Xprint:typer
つけてホントかどうか見てみる。
$ scalac -Xprint:typer sample1.scala
↓こんなの出ました。
[[syntax trees at end of typer]] // sample1.scala
package sample1 {
object Main extends AnyRef with App {
def <init>(): sample1.Main.type = {
Main.super.<init>();
()
};
private[this] val seq: Seq[Int] = collection.this.Seq.apply[Int](1, 2, 3);
<stable> <accessor> def seq: Seq[Int] = Main.this.seq;
Main.this.seq.foreach[Unit](((i: Int) => scala.this.Predef.println(i)))
}
}
foreachになってますね。
次に、自前のクラスをfor式で回してみる。
foreachのシグニチャはこんなの。
def foreach(f: (A) ⇒ Unit): Unit
これを実装すればOKのはず。
package sample2
object Main extends App {
object Eachable {
import scala.util.Random
private val random = new Random
// ランダムな数値をエサに3回「f」を呼び出す。
def foreach(f: (Int) => Unit) = {
f(random.nextInt)
f(random.nextInt)
f(random.nextInt)
}
}
for (i <- Eachable) println(i)
}
レッツ、コンパイル。
[[syntax trees at end of typer]] // sample2.scala
package sample2 {
object Main extends AnyRef with App {
def <init>(): sample2.Main.type = {
Main.super.<init>();
()
};
object Eachable extends scala.AnyRef {
def <init>(): sample2.Main.Eachable.type = {
Eachable.super.<init>();
()
};
import scala.util.Random;
private[this] val random: scala.util.Random = new scala.util.Random();
<stable> <accessor> private def random: scala.util.Random = Eachable.this.random;
def foreach(f: Int => Unit): Unit = {
f.apply(Eachable.this.random.nextInt());
f.apply(Eachable.this.random.nextInt());
f.apply(Eachable.this.random.nextInt())
}
};
Main.this.Eachable.foreach(((i: Int) => scala.this.Predef.println(i)))
}
}
foreachになってますね。
動かしてみると、3回テキトーな数字が表示されます。
gistにコード全文。