在this answer我給的,爲什麼Writes
是不是仿函數,也就是爲什麼如果我們有一個Writes[A]
和功能A => B
我們不能創造同樣的方式Writes[B]
一個快速的解釋,我們可以同Reads
。
當我在回答說明,Writes
不是一般的(協)函子,但它是一個逆變函子,這意味着,如果我們有一個Writes[A]
和功能B => A
,我們可以創建Writes[B]
。
Format
涵括既Reads
和Writes
的功能,這意味着它既不是仿函數也不是逆變函子,但它是一個不變的算符(和它的真正的唯一一種與你會碰到一個不變的函子實例在Play中)。
要明白爲什麼會是這樣,假設我們有以下兩種類型:
case class Foo(i: Int, s: String)
case class Bar(s: String, i: Int)
並假設我們已經有了一個Format
實例Foo
:
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val fooFormat = Json.format[Foo]
但是,不管是什麼原因我們不能用Bar
以同樣的方式創建一個 - 我們想從Foo
的那個中得到它。這是不夠的,我們要懂得從Foo
,反之亦然創建Bar
,但如果我們可以是雙向的,我們可以使用Format
不變函子:
implicit val barFormat = fooFormat.inmap[Bar](
foo => Bar(foo.s, foo.i),
bar => Foo(bar.i, bar.s)
)
這是因爲我們能想到的Format
作爲一種雙向管道,允許我們投入JsValue
並取出一些A
,或放入該A
並取出JsValue
。如果我們想要將雙向管道Format[A]
轉換成雙向管道Format[B]
,我們需要雙方適配器(即,A => B
和B => A
)。