在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
有人可以解释一下吗?谢谢!
答案 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
在没有隐式的情况下不会编译,因为即使你知道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!
}
由于隐式参数在方法中可用作隐含,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问题。