【问题标题】:Create Writes and Format of Case Class创建案例类的写入和格式
【发布时间】:2014-02-11 22:49:21
【问题描述】:

对于这个案例类:

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] 来获取/定义ReadsWrites

val peopleFormat: Format[People] = ...?

【问题讨论】:

    标签: json scala playframework


    【解决方案1】:

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

    您可以将Writes[A] 视为类似于A =&gt; JsValue 的东西。但假设我有一个A =&gt; JsValue 和一个A =&gt; B。尝试想出一些方法来组合这些函数以获得B =&gt; JsValue——这是不可能的。

    另一方面,Reads[A] 有点像JsValue =&gt; A,并且是一个函子——它有一个map 方法,它接受A =&gt; B,将它与Reads[A] / JsValue =&gt; A 组合起来, 并返回 Reads[B] / JsValue =&gt; B

    然而,

    Writes 是一个逆变 函子,幸运的是Play knows that。当F 是逆变函子时,F[A] 有一个方法contramap[B](f: B =&gt; A) 而不是通常的map[B](f: A =&gt; 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 =&gt; Set[Int]。将它们与contramap 结合起来,我们就得到了Writes[People]

    【讨论】:

    • 谢谢,特拉维斯。如果可能的话,您能否展示如何使用unlift 编写Writes[People]?另外,Format[People] 会是什么样子?再次感谢。
    • 更新了一些关于contramap 参数的附加信息。此外,当您不处理案例类的unapply 之类的东西时,您不需要unlift,并且一旦您获得隐含的ReadsWrites 实例,您就已经获得了Format[People]在范围内,感谢隐含的Format.GenericFormat
    • 所以Writes[Set[Int]].contramap(f) 其中f 有签名:Set[Int] =&gt; People_.names 扩展为 (x =&gt; x.names)。而contra in contramap 意味着,对于function: B =&gt; A,我们传入Person =&gt; Set[Int],但实际上发生了相反的情况-Set[Int] =&gt; Person
    • 不完全是。将ReadsWrites 视为AJsValue 之间的管道。 contramapB =&gt; A 放在Writes 管道的前面mapReads 管道之后放置一个A =&gt; B
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多