/ / Відтворити вихідний файл “Reads.scala” із використанням узагальненого обмеження типу - scala, playframework, playframework-2.0, playframework-2.1

Відтворити вихідний файл "Reads.scala" Використання узагальненого обмеження типу - scala, playframework, playframework-2.0, playframework-2.1

У вихідному файлі фреймворку 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 для отримання додаткової інформації.