19.4. Własne typy w pętli i wyrażeniu for
Skoro pętlom i wyrażeniom for odpowiadają wyrażenia zawierające wywołania odpowiednich metod, to klasy zawierające definicje takich metod mogą być używane w pętlach i/lub wyrażeniach for. W pliku ThreeValues1.scala zdefiniowana jest klasa ThreeValues1, która posiada definicję pętli foreach.
Plik ThreeValues1.scala: case class ThreeValues1[T](a: T, b: T, c: T) { def foreach(f: T => Unit) { f(a); f(b); f(c) } }
Wobec tego instancja tej klasy może być użyta w poniższej pętli for. Po pętli for pokazane jest wyrażenie działające analogicznie, a wykorzystujące jawne wywołanie metody foreach.
scala> val a = new ThreeValues1(1,2,3) a: ThreeValues1[Int] = ThreeValues1(1,2,3) scala> for (x <- a) println(x) 1 2 3 scala> a.foreach{ case x => println(x) } 1 2 3
Nie każda postać pętli lub wyrażenia for jest dozwolona w przypadku użycia instancji klasy ThreeValues1, gdyż w klasie tej brakuje pozostałych metod potrzebnych przy przekształcaniu pętli for. Na przykład brak metody map powoduje, że następujące wyrażenie for nie kompiluje się.
scala> for (x <- a) yield x*x <console>:12: error: value map is not a member of ThreeValues1[Int] for (x <- a) yield x*x ^
Plik ThreeValues2.scala zawiera definicję klasy, która obok metody foreach, ma zdefiniowaną również metodę map.
Plik ThreeValues2.scala: case class ThreeValues2[T](a: T, b: T, c: T) { def foreach(f: T => Unit) { f(a); f(b); f(c) } def map[S](f: T => S) = new ThreeValues2(f(a), f(b), f(c)) }
W rezultacie, zarówno poniższa pętla for, jak i wyrażenie for kompilują i wykonują się.
scala> val b = new ThreeValues2(1,2,3) b: ThreeValues2[Int] = ThreeValues2(1,2,3) scala> for (x <- b) println(x) 1 2 3 scala> for (x <- b) yield x*x res4: ThreeValues2[Int] = ThreeValues2(1,4,9)
Instancje klasy ThreeValues2 mogą być użyte w niektórych wyrażeniach for, ale nie wszystkich, gdyż nie posiadają metod flatMap oraz withFilter. Przykładowo, poniższe wyrażenia for nie kompilują się.
scala> val c = new ThreeValues2(4,5,6) c: ThreeValues2[Int] = ThreeValues2(4,5,6) scala> for (x <- b; y <- c) yield x*y <console>:13: error: value flatMap is not a member of ThreeValues2[Int] for (x <- b; y <- c) yield x*y ^ scala> for (x <- b if x > 2) yield x*4 <console>:12: error: value filter is not a member of ThreeValues2[Int] for (x <- b if x > 2) yield x*4 ^