2

Play フレームワークのソース ファイルでは、トレイト Reads[A] 内に次のメソッドがあります。

def andThen[B](rb: Reads[B])(implicit witness: A <:< JsValue): Reads[B] =
    rb.compose(this.map(witness))

そして、次のような map メソッド:

def map[B](f: A => B): Reads[B] =
    Reads[B] { json => self.reads(json).map(f) }

証人の型は A <:< JsValue (一般化された型の制約) です。では、map メソッドのパラメーターが関数 f: A => B を取るときに、引数として map メソッドに渡されるのはなぜですか??

誰か説明してくれませんか?ありがとう!

4

1 に答える 1

4

これは、このタイプの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は、暗黙的なものなしではコンパイルされません。証拠のおかげだわかっていても、型システムはそうではないからです。あなたはそれをキャストすることができます、それは確実に機能するでしょう: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()、関数が関与していることを知る必要はありません。

ただし、型システムは暗黙的のみを使用して 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]JsValueB

詳細については、SO に関する一般化された型制約の質問を参照してください。

于 2013-07-07T13:05:44.097 に答える