2

В Play рамки исходного файла, есть следующий метод внутри признака читает [A]:Play исходный файл использовать «Reads.scala» обобщенного типа ограничения

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

и метод карты, как это:

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

свидетель типа А <: < JsValue (который представляет собой обобщенный тип ограничения). Итак, как получилось, что он передается в метод карты в качестве аргумента, когда параметр метода карты принимает функцию f: A => B ??

Может ли кто-нибудь объяснить? Благодаря!

ответ

4

Это потому, что этот тип свидетеля также является функцией. Он объявлен в Predef как:

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

Так A <:< JsValue также функция (A) => JsValue. Вы можете задаться вопросом, что делает функция: она ничего не делает, она принимает A и напрямую возвращает ее (как JsValue).

Чтобы понять, почему это полезно рассмотреть этот пример:

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()` 
} 

Последний метод makeBip2 не будет компилироваться без неявное, потому что даже если вы знаете, что a является Root благодаря свидетельствам, типа системы нет. Вы могли бы его бросить, это было бы обязательно:

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

Но это не так. Если бы у вас был способ, который вы конвертируете a в Root ... но подождите, вы это сделаете: сами доказательства!

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

И поскольку неявные параметры доступны как implicits в рамках метода, a.bip() будут автоматически преобразованы в ev(a).bip() и вы никогда не должны знать, функция была вовлечена.

Однако система типа использует только неявный для разрешения A в JsValue, но не Seq[A] в Seq[JsValue] или ее Reads[A] в Reads[JsValue].

Так в вас случае, this.map(witness) просто делает систему типа понимают, что Reads[A] является Reads[JsValue], применяя эту функцию, которая ничего не делает, так что он может быть составлен с чем-то, что принимает JsValue и возвращает B.

См. Вопрос Generalized type constraits на SO для получения дополнительной информации.

Смежные вопросы