创建案例类的写入和格式



对于这种情况类:

case class People(names: Set[Int])

特拉维斯·布朗(Travis Brown)解释了如何创建PeopleReads: Reads[People]这个答案:

implicit val PeopleReads = 
       (__  "names").read[Set[Id]].map(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)))

如何解决此错误?

另外,我如何在获取/定义ReadsWrites的地方编写Format[People]

val peopleFormat: Format[People] = ...

好问题!不能使用map的原因是因为Writes不是函子。

你可以把Writes[A]想象成有点像A => JsValue的东西。但是假设我有一个A => JsValue和一个A => B.尝试想出一些方法来组合这些函数以获得B => JsValue - 这是不可能的。

另一方面,Reads[A]有点像JsValue => A,并且是一个函子——它有一个map方法,它接受一个A => B,用Reads[A]/JsValue => A组成它,并返回一个Reads[B]/JsValue => B

然而,Writes是一个逆变函子,幸运的是,Play知道这一点。当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] .

最新更新