15.4. Metody apply, unapply i unapplySeq

Utworzenie klasy przypadku może spowodować dodanie do jej obiektu towarzyszącego (a jeśli nie był jawnie zdefiniowany, to także utworzenie go) metod apply oraz jednej z metod unapply lub unapplySeq.

Metoda apply ma listę parametrów odpowiadającą liście elementów klasy i pozwala tworzyć instancje klasy w sposób przypominający tworzenie tych instancji za pomocą operatora new, tyle że z pominięciem tego operatora.

scala> val e1 = E.apply(1,"e",3L)
e2: E = E(1,e,3)

scala> val e2 = E(1,"e",3L)
e2: E = E(1,e,3)

Metoda apply nie jest tworzona w przypadku abstrakcyjnych klas przypadku.

scala> abstract case class F(a: Int)
defined class F

scala> F.apply(1)
<console>:13: error: value apply is not a member of object F
       F.apply(1)
         ^

Metody unapply i unapplySeq służą do obsługi przez klasę przypadku dopasowywania wzorców i są generowane w sposób odzwierciedlający liczbę i typy elementów klasy. Dzięki temu można stosować wzorce o nazwach takich jak nazwy klas przypadku i o parametrach odpowiadających elementom klas.

Plik CaseClassF.scala:
case class F0()
case class F1(x: Int)
case class F2(x: Int, y: Int)
case class F3(x: String*)
case class F4(x: Int, z: String*)
def testF(x: Any):String = x match {
  case F0() => "F0"
  case F1(y) => s"F1($y)"
  case F2(2,_) => "F2(2,?)"
  case F3() => "F3()"
  case F3(a) => s"F3($a)"
  case F3(a,b) => s"F3($a,$b)"
  case F4(a) => s"F4($a)"
  case F4(a,b) => s"F4($a,$b)"
  case F4(a,b,_*) => s"F4($a,$b,...)"
  case _ => ""
}

Plik CaseClassF.scala zawiera definicje kilku klas przypadku oraz definicję metody testF, w której użyte są wzorce dopasowujące instancje tych klas.

scala> :load CaseClassF.scala
Loading CaseClassF.scala...
defined class F0
defined class F1
defined class F2
defined class F3
defined class F4
testF: (x: Any)String

scala> testF(F0())
res2: String = F0

scala> testF(F1(1))
res3: String = F1(1)

scala> testF(F2(2,3))
res4: String = F2(2,?)

scala> testF(F3("a","b"))
res5: String = F3(a,b)

scala> testF(F4(5))
res6: String = F4(5)

scala> testF(F4(5,"a"))
res7: String = F4(5,a)

scala> testF(F4(5,"a","b"))
res8: String = F4(5,a,...)

Przykład z pliku CaseClassConflict.scala pokazuje konflikt między jawnie zdefiniowaną metodą, a metodą generowaną domyślnie w obiekcie towarzyszącym. Obiekt F5 definiuje metodę o nazwie apply i liście parametrów takiej, jak lista parametrów klasy F5.

Plik CaseClassConflict.scala:
case class F5(a: Int)
object F5 {
  def apply(a: Int) = ()
}

Próba kompilacji pliku CaseClassConflict.scala nie udaje się.

$ scalac CaseClassConflict.scala
CaseClassConflict.scala:1: error: method apply is defined twice
  conflicting symbols both originated in file 'H:\jps2\examples\CaseClassConflict.scala'
case class F5(a: Int)
           ^
one error found

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.