これは、このタイプのwitnessも関数であるためです。次のように宣言され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()
、関数が関与していることを知る必要はありません。
ただし、型システムは暗黙的のみを使用して anA
を aに解決し、 aをaまたは aに解決しJsValue
ません。Seq[A]
Seq[JsValue]
Reads[A]
Reads[JsValue]
したがって、あなたの場合、何もしない関数を適用することで aが a であるthis.map(witness)
ことを型システムに理解させるだけで、 a を取り、 aを返すもので構成できます。Reads[A]
Reads[JsValue]
JsValue
B
詳細については、SO に関する一般化された型制約の質問を参照してください。