我为 Scanamo
制作了一个通用的 DynamoFormat
,它将放置任何具有 Circe
的 Encoder
的对象,并且Decoder
作为 Json 字符串定义到数据库中。
import com.gu.scanamo.DynamoFormat
import io.circe.parser.parse
import io.circe.syntax._
import io.circe.{Decoder, Encoder}
object JsonDynamoFormat {
def forType[T: Encoder: Decoder]: DynamoFormat[T] = DynamoFormat.coercedXmap[T, String, Exception] {
s => parse(s).flatMap(_.as[T]).fold(err => throw err, obj => obj)
} {
obj => obj.asJson.noSpaces
}
}
然后我添加了隐式转换(到同一个对象 JsonDynamoFormat
)以自动提供这些格式化程序。
implicit def jsonToFormat[T: Encoder: Decoder]: DynamoFormat[T] = JsonDynamoFormat.forType[T]
当我导入它时,编译器成功解析格式化程序,但是在运行时我在 JsonDynamoFormat
中出现堆栈溢出,其中调用 jsonToFormat
和 forType
> 无限交替:
Exception in thread "main" java.lang.StackOverflowError
at JsonDynamoFormat$.forType(JsonDynamoFormat.scala:12)
at JsonDynamoFormat$.jsonToFormat(JsonDynamoFormat.scala:9)
at JsonDynamoFormat$.forType(JsonDynamoFormat.scala:13)
at JsonDynamoFormat$.jsonToFormat(JsonDynamoFormat.scala:9)
...
我真的无法理解这里发生了什么。有人能解释一下吗?
最佳答案
调试 Scala 隐式错误可能非常繁重。以下是一些可以提供帮助的建议:
启用
scalacOptions ++= Seq("-Xlog-implicits")
编译器选项。这将打印隐式搜索日志,并且有助于了解隐式链断裂的确切位置。添加说明
libraryDependencies ++= Seq(compilerPlugin("io.tryp" %% "splain" % "0.2.4"))
提高隐式调试日志的可读性。
一般来说,一般派生类型类在运行时的堆栈溢出是隐式解析错误的标志。这通常意味着编译器找到了几个循环依赖的隐式并使用其中一个来满足另一个,反之亦然。
通常这种情况是在编译时识别的,并且编译会产生“发散隐式”错误,但该错误可能是误报,因此库作者通常使用 Lazy
这样的技术来规避它。来自 Shapeless 的类型类。但是,如果存在实际错误的循环隐式,这将导致运行时错误,而不是编译时错误。
关于scala - 具有隐式转换的类型类中的堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45880638/