这是因为这种类型的见证也是一个函数。它被声明Predef
为:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
所以A <:< JsValue
也是一个函数(A) => JsValue
。你可能想知道这个函数做了什么:它什么都不做,它接受 aA
并直接返回它(作为 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()
并且您永远不需要知道涉及的函数。
但是,类型系统仅使用隐式将 an 解析A
为 a JsValue
,而不是 a Seq[A]
into aSeq[JsValue]
或 a Reads[A]
into a Reads[JsValue]
。
因此,在您的情况下,this.map(witness)
只需通过应用什么都不做的函数来让类型系统了解 aReads[A]
是 a Reads[JsValue]
,这样它就可以与接受 aJsValue
并返回 a 的东西组合在一起B
。
有关更多信息,请参阅 SO 上的广义类型约束问题。