2017-08-25 32 views
1

我的Scanamo将放有任何对象进行通用DynamoFormatCirceEncoderDecoder定义到数据库作为一个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 
    } 
} 

然后我添加了一个隐式转换(与object JsonDynamoFormat相同)以自动提供这些格式化程序。

implicit def jsonToFormat[T: Encoder: Decoder]: DynamoFormat[T] = JsonDynamoFormat.forType[T] 

当我将其导入,编译器将解析格式化成功,但在运行时我得到了JsonDynamoFormat堆栈溢出,其中调用jsonToFormatforType备用无限:

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) 
    ... 

我真的不能明白这里发生了什么。任何人都可以阐明这一点吗?

+0

我不知道会发生什么,如果你让'def forType'隐式并移除'implicit def jsonToFormat'。看起来第二个是非常多余的。 – Haspemulator

+0

@Haspemulator,有趣的是它无法编译,虽然函数签名确实看起来是一样的。奇怪的。 –

+1

我认为这种失败是解决问题根源的关键。启用'scalacOptions ++ = Seq(“ - Xlog-implicits”)'获得隐式解析日志(可能是很多输出),并且可以选择'libraryDependencies ++ = Seq(compilerPlugin(“io.tryp”%%“ splain“%”0.2.4“))'使输出更好。这可能有助于解释为什么隐式未找到。 – Haspemulator

回答

1

调试斯卡拉implicits错误可以说是相当繁重的。下面是一些建议,可以帮助:

  • 启用scalacOptions ++= Seq("-Xlog-implicits")编译器选项。这将打印隐式搜索日志,并且可以用于了解隐式链断裂的确切位置。

  • 添加splain libraryDependencies ++= Seq(compilerPlugin("io.tryp" %% "splain" % "0.2.4"))改善隐含的调试日志的可读性。

一般来说,在运行时使用泛型派生类型类的堆栈溢出是错误隐式解析的标志。这通常意味着编译器已经找到了几个循环依赖的含义,并使用其中的一个来满足另一个,反之亦然。

通常情况下,编译时会识别出这种情况,编译会产生“diverging implicits”错误,但是这种错误可能是误报,因此库作者通常使用类似Lazy类型的技术来避免它。但是,如果出现实际的错误循环含义,这将导致运行时错误,而不是编译时错误。