У вихідному файлі фреймворку Play існує такий спосіб всередині ознаки Читання [A]:
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) }
свідок має тип A <: <JsValue (що є узагальненим обмеженням типу). Так як же це передається в метод map як аргумент, коли параметр методу map приймає функцію f: A => B ??
Хтось може пояснити? Дякую!
Відповіді:
4 для відповіді № 1Це тому, що цей тип свідка також є функцією. Про це заявлено в 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
до a Root
... але зачекайте, ви робите: самі докази!
def makeBip4[A](a: A)(implicit ev: A <:< Root) {
ev(a).bip() // works!
}
І оскільки неявні параметри доступні як імпліцити в методі, a.bip()
буде автоматично перетворено в ev(a).bip()
і ніколи не потрібно знати, яка функція була задіяна.
Однак система типів використовує лише неявний для розв'язання A
в a JsValue
, але не а Seq[A]
в a Seq[JsValue]
або a Reads[A]
в a Reads[JsValue]
.
Тож у вашому випадку, this.map(witness)
просто дає зрозуміти системі типів, що a Reads[A]
це Reads[JsValue]
застосовуючи ту функцію, яка нічого не робить, щоб її можна було скласти з чимось, що займає a JsValue
і повертає a B
.
Див Узагальнені обмеження типу питання про SO для отримання додаткової інформації.