2017-08-25 71 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類型的技術來避免它。但是,如果出現實際的錯誤循環含義,這將導致運行時錯誤,而不是編譯時錯誤。