/ / Quelldatei "Reads.scala" unter Verwendung der allgemeinen Typeinschränkung abspielen - scala, playframework, playframework-2.0, playframework-2.1

Play Quelldatei "Reads.scala" Verwendung der generalisierten Typ Einschränkung - Scala, Playframework, Playframework-2.0, Playframework-2.1

In der Play Framework-Quelldatei gibt es die folgende Methode in der Eigenschaft Reads [A]:

def andThen[B](rb: Reads[B])(implicit witness: A <:< JsValue): Reads[B] =
rb.compose(this.map(witness))

und eine Kartenmethode wie diese:

def map[B](f: A => B): Reads[B] =
Reads[B] { json => self.reads(json).map(f) }

Zeuge ist vom Typ A <: <JsValue (eine verallgemeinerte Typeinschränkung). Wie kommt es also, dass es als Argument an die Map-Methode übergeben wird, wenn der Parameter der Map-Methode eine Funktion f annimmt: A => B ??

Könnte jemand erklären? Vielen Dank!

Antworten:

4 für die Antwort № 1

Dies liegt daran, dass dieser Typ Zeuge auch eine Funktion ist. Es ist in deklariert Predef wie:

sealed abstract class <:<[-From, +To] extends (From => To) with Serializable

Damit A <:< JsValue ist auch eine Funktion (A) => JsValue. Sie mögen sich fragen, was die Funktion tut: Sie tut nichts, sie braucht eine A und gibt es direkt zurück (als JsValue).

Um zu sehen, warum dies nützlich ist, betrachten Sie dieses Beispiel:

sealed trait Root { def bip() { println("bip") } }

def makeBip[A <: Root](a: A) {
a.bip() // works because a is known to the type system to be a Root
}

def makeBip2[A](a: A)(implicit ev: A <:< Root) {
a.bip() // works, because implicit resolution turns it into `ev(a).bip()`
}

Die letzte Methode makeBip2 würde nicht ohne das implizite kompilieren, obwohl Sie weiß das a ist ein Root Dank der Beweise funktioniert das Typensystem nicht. Sie könnten es gießen, es würde sicher funktionieren:

def makeBip3[A](a: A)(implicit ev: A <:< Root) {
a.asInstanceOf[Root].bip() // ugly
}

Aber das fühlt sich nicht richtig an. Wenn Sie nur eine Möglichkeit hätten, zu konvertieren a zu einem Root... aber warten Sie, Sie tun: die Beweise selbst!

def makeBip4[A](a: A)(implicit ev: A <:< Root) {
ev(a).bip() // works!
}

Und da implizite Parameter als implizite in der Methode verfügbar sind, a.bip() wird automatisch konvertiert nach ev(a).bip() und Sie müssen nie wissen, dass eine Funktion beteiligt war.

Das Typsystem verwendet jedoch nur das Implizite zum Auflösen von A in ein JsValueaber nicht a Seq[A] in ein Seq[JsValue] oder ein Reads[A] in ein Reads[JsValue].

Also in deinem Fall, this.map(witness) macht dem Typensystem nur klar, dass a Reads[A] ist ein Reads[JsValue] durch Anwenden dieser Funktion, die nichts tut, so dass sie mit etwas komponiert werden kann, das a benötigt JsValue und gibt a zurück B.

Siehe die Verallgemeinerte Typbeschränkungen Frage zu SO für mehr.