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
                 ^

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.