试图为这个案例类编写一个json格式化程序
case class OptionRange[+T](start: Option[T], end: Option[T])
这就是我到目前为止所拥有的
implicit def fmt[T <: OptionRange[_]](implicit fmt: Format[Option[T]]): Format[OptionRange[T]] = new Format[OptionRange[T]] {
def reads(json: JsValue): JsSuccess[OptionRange[T]] = JsSuccess(new OptionRange[T] (
(json \ "start").as[Option[T]],
(json \ "end").as[Option[T]]
))
def writes(i: OptionRange[T]) = JsObject(Seq(
"start" -> Json.toJson(i.start),
"end" -> Json.toJson(i.end)
))
}
这段代码编译,但当我尝试格式化OptionRange[Int]
时,我得到一个错误,没有隐式格式可用。
如何编写隐式范围内可用的格式?
你有一些循环类型的定义。
在我看来,你打算在这种情况下将T
评估为Int
。但是,在函数定义中,您已经约束了[T <: OptionRange[_]]
。因此,Scala认为T
必须是某种东西的OptionRange
。
当你转到函数(implicit fmt: Format[Option[T]])
的隐含参数时,这会变得更加复杂。如果T
是OptionRange[_]
,那么你告诉编译器需要一个Format[Option[OptionRange[_]]]
而不是Format[Option[_]]
。您的函数不能成为Format
的来源,因为无法对其进行求值以提供隐含的必需。
解决方案是停止约束T
。
implicit def fmt[T](implicit fmt: Format[Option[T]]) ...
然后,当您尝试将OptionRange
格式化为json时:
scala> import play.api.libs.json._
import play.api.libs.json._
scala> case class OptionRange[+T](start: Option[T], end: Option[T])
defined class OptionRange
scala> implicit def fmt[T](implicit fmt: Format[Option[T]]): Format[OptionRange[T]] = new Format[OptionRange[T]] {
| def reads(json: JsValue): JsSuccess[OptionRange[T]] = JsSuccess(new OptionRange[T] (
| (json \ "start").as[Option[T]],
| (json \ "end").as[Option[T]]
| ))
| def writes(i: OptionRange[T]) = JsObject(Seq(
| "start" -> Json.toJson(i.start),
| "end" -> Json.toJson(i.end)
| ))
| }
fmt: [T](implicit fmt: play.api.libs.json.Format[Option[T]])play.api.libs.json.Format[OptionRange[T]]
scala> Json.toJson(OptionRange(Some(1), Some(2)))
res0: play.api.libs.json.JsValue = {"start":1,"end":2}
这是使用play-framework 2.3.9
,Scala 2.11.8
执行此操作的方法:
import play.api.libs.json._ // JSON library
import play.api.libs.json.Reads._ // Custom validation helpers
import play.api.libs.functional.syntax._ // Combinator syntax
case class OptionRange[+T](start: Option[T], end: Option[T])
object Hello extends App {
implicit def formatOptionRange[T](implicit formatT: Format[T]): Format[OptionRange[T]] =
(
(JsPath \ "start").formatNullable[T] and
(JsPath \ "end").formatNullable[T]
)(OptionRange.apply, unlift(OptionRange.unapply))
println(Json.toJson(OptionRange(Some(1), Some(2))))
}
//Prints:
//{"start":1,"end":2}
这是关于format的文档。