播放源文件“Reads.scala”使用广义类型约束

时间:2013-07-07 03:14:18

标签: scala playframework playframework-2.0 playframework-2.1

在Play框架源文件中,特征Reads [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&lt;:&lt; JsValue(这是一个通用类型约束)。那么,当map方法的参数采用函数f时,它是如何作为参数传递给map方法的:A =&gt; B 12

有人可以解释一下吗?谢谢!

1 个答案:

答案 0 :(得分: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在没有隐式的情况下不会编译,因为即使知道aRoot,由于证据,类型系统没有。你可以施展它,它肯定会起作用:

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!
}

由于隐式参数在方法中可用作隐含,a.bip()将自动转换为ev(a).bip(),您永远不需要知道涉及的函数。

但是,类型系统仅使用隐式将A解析为JsValue,而不是将Seq[A]解析为Seq[JsValue]Reads[A]进入Reads[JsValue]

所以在你的情况下,this.map(witness)只是让类型系统通过应用那个什么也不做的函数来理解Reads[A]Reads[JsValue],这样它就可以用获取JsValue并返回B

有关详情,请参阅有关SO的Generalized type constraits问题。