我有以下代码:
import play.api.libs.json._
object Test {
sealed trait T
case class A(s: String) extends T
implicit val writesA: OWrites[A] = Json.writes[A]
implicit val writesT: OWrites[T] = Json.writes[T]
def main(args: Array[String]): Unit = {
val x = A("str")
println(Json.toJson[T](x)(writesT))
}
}
运行时会导致StackOverflowError
。
如果我在lazy
前面添加writesT
,则StackOverflowError
消失,一切正常:
import play.api.libs.json._
object Test {
sealed trait T
case class A(s: String) extends T
implicit val writesA: OWrites[A] = Json.writes[A]
implicit lazy val writesT: OWrites[T] = Json.writes[T]
def main(args: Array[String]): Unit = {
val x = A("str")
println(Json.toJson[T](x)(writesT))
}
}
当我将StackOverflowError
移到implicit
函数中时,main
也消失了:
import play.api.libs.json._
object Test {
sealed trait T
case class A(s: String) extends T
def main(args: Array[String]): Unit = {
implicit val writesA: OWrites[A] = Json.writes[A]
implicit val writesT: OWrites[T] = Json.writes[T]
val x = A("str")
println(Json.toJson[T](x)(writesT))
}
}
有人可以向我解释为什么我在第一种情况下会得到StackOverflowError
吗?
我怀疑它与初始化顺序以及play-json在后台使用的宏有关。但是如果是这样的话,我不明白为什么使用lazy
会有所帮助,因为代码仍应在编译时生成,并且仅在以后的运行时对其进行评估不应更改任何内容。显然,在以后的情况下,writesA
找到了writesT
实例,但在第一种情况下却没有。为什么添加lazy
可以解决隐式分辨率和宏代码生成的编译时问题?
这是一个完全不同的问题吗?
我正在使用Scala 2.12.3和play-json 2.6.2。