对于本案例类:
case class People(names: Set[Int])
Travis Brown解释了如何在此answer创建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)))
如何解决此错误?
另外,我如何在Format[People]
和Reads
得到/定义的地方Writes
写一下:
val peopleFormat: Format[People] = ...
?
答案 0 :(得分:2)
好问题!您无法使用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 knows that。当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]
。