对于此案例类:
case class People(names: Set[Int])
特拉维斯·布朗(Travis Brown)解释了如何创建PeopleReads:Reads[People]此答案:
PeopleReads:Reads[People]
implicit val PeopleReads = (__ \ "names").read[Set[Id]].map(People)
但是,我正在尝试实现PeopleWrites: Writes[People]:
PeopleWrites: Writes[People]
implicit val PeopleWrites: Writes[People] = (JsPath \ "names").write[Set[Int]].map(unlift(x => Some((x.names)))
出现以下编译时错误:
scala> People( Set(1,2,3)) res5: People = People(Set(1, 2, 3)) scala> implicit val PeopleWrites: Writes[People] = (JsPath \ "names").write[Set[Int]].map(unlift(x => Some((x.names)))) <console>:21: error: value map is not a member of play.api.libs.json.OWrites[Set[Int]] implicit val PeopleWrites: Writes[People] = (JsPath \ "names").write[Set[Int]]. map(unlift(x => Some((x.names)))
如何解决此错误?
另外,我怎么写我Format[People]在哪里得到/定义了Reads和Writes:
Format[People]
Reads
Writes
val peopleFormat: Format[People] = ...?
val peopleFormat: Format[People] = ...
好问题!您不能使用的原因map是因为Writes它不是函子。
map
您可以将其Writes[A]视为类似A => JsValue。但是,假设我有一个A => JsValue和一个A => B。尝试想出一些方法来构成这些函数以获得一个B => JsValue—这是不可能的。
Writes[A]
A => JsValue
A => B
B => JsValue
Reads[A]另一方面,有点像JsValue => A,并且是一个函子-它具有一种map方法,该方法采用a A => B并将其与Reads[A]/ 组成JsValue => A并返回Reads[B]/ JsValue => B。
Reads[A]
JsValue => A
Reads[B]
JsValue => B
Writes但是,它是一个 协变 函子,幸运的是Play知道这一点。当F是逆函子时,F[A]有一个方法contramap[B](f: B => A)代替了通常的方法map[B](f: A => B)。所以你可以这样写:
F
F[A]
contramap[B](f: B => A)
map[B](f: A => B)
case class People(names: Set[Int]) import play.api.libs.json._ import play.api.libs.functional.syntax._ implicit val PeopleWrites: Writes[People] = (__ \ 'names).write[Set[Int]].contramap(_.names)
这(__ \ 'names).write[Set[Int]]是一个Writes[Set[Int]]并且(_.names)是一个函数People => Set[Int]。与他们结合在一起contramap给我们一个Writes[People]。
(__ \ 'names).write[Set[Int]]
Writes[Set[Int]]
(_.names)
People => Set[Int]
contramap
Writes[People]