最近リファクタリングとか微妙な不具合修正やってるほさかです。 Scala の for は Java のものとはだいぶ様子が違います。そこで仕様を読みながらもう一度forについて学びます。
ここではscala-lang.orgを 読みながら自分なりの説明を書いてますので、気になる方はscala-lang.orgを読みましょう。
for とは
2種類のforがあります。 for内包表記 と forループ です。
for ( enum ) e
forループは 列挙enum の各要素に対して 式e を実行します。
REPLの実行例
scala> for (x <- List(1, 2, 3)) print(x) 123
for ( enum ) yield e
for内包表記は 列挙enum の各要素に対して 式e を実行し、その結果を集めて返します。
REPLの実行例
scala> for (x <- List(1, 2, 3)) yield -x res0: List[Int] = List(-1, -2, -3)
列挙はまず ジェネレーター から始まります。その後には、さらに ジェネレーター、 値の定義 、ガード を書けます。
ジェネレーター p <- e
は式eのうちパターンpにマッチするものをバインドします。
マッチしない物は無視されます。
値の定義 はval
を省略する以外はいつもどおりです。
ガード if e
は列挙のバインドを e が真のものに限定します。
これらはそれぞれ map flatMap withFilter foreach で実装されています。 これらのメソッドを実装したものであればジェネレーターにできます。
変換ルール
for内包表記 for (p <- e) yield e′
は e.map { case p => e′ }
に変換されます。
forループ for (p <- e) e′
は e.foreach { case p => e′ }
に変換されます。
for内包表記 for (p <- e; p′ <- e′;…) yield e″
(…
は空かジェネレーターか値の定義かガード)
は e.flatMap { case p => for (p′ <- e′;…) yield e″ }
に変換されます。
forループ for (p <- e; p′ <- e′;…) e″
(…
は空かジェネレーターか値の定義かガード)
は e.foreach { case p => for (p′ <- e′;…) e″ }
に変換されます。
ガード if g
をともなう ジェネレーター p <- e
は 一つのジェネレーター p <- e.withFilter((x1,…,xn) => g)
(x1,…,xn
は p の変数) に変換されます。
値の定義 p′ = e′
をともなう ジェネレーター p <- e
は 値のペアを持つジェネレーターをともなって変換されます。
(p, p′) <- for (x@p <- e) yield { val x′@p′ = e′; (x, x′) }
おわり
forやScalaに限らず疑問があれば仕様を読めば良いと思います。