2015-09-07 43 views
8

我有以下代碼,它使用spray-json通過parseJson方法將一些JSON反序列化爲一個case類。Scala在解決implicits時如何使用顯式類型?

根據隱式JsonFormat [MyCaseClass]被定義,其中(在線或從同伴對象導入),以及是否存在被定義,當它提供一個明確的類型,代碼可能不能編譯。

我不明白爲什麼從伴侶對象導入隱式要求它在定義時具有顯式類型,但如果我將它放在內聯中,情況並非如此?

有趣的是,IntelliJ在所有情況下都正確地定位了隱式參數(通過cmd-shift-p)。

我正在使用Scala 2.11.7。

斷碼 - 從同伴對象通配符進口,推斷類型:

import SampleApp._ 
import spray.json._ 

class SampleApp { 
    import MyJsonProtocol._ 
    val inputJson = """{"children":["a", "b", "c"]}""" 
    println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}") 
} 

object SampleApp { 
    case class MyCaseClass(children: List[String]) 

    object MyJsonProtocol extends DefaultJsonProtocol { 
    implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass) 
    } 
} 

結果:

Cannot find JsonReader or JsonFormat type class for SampleAppObject.MyCaseClass 

注意的是,同樣的事情發生與myCaseClassSchemaFormat隱含的一個明確的進口。

工作守則#1 - 從同伴對象通配符進口,顯式類型:

在同伴對象添加一個顯式類型的JsonFormat導致代碼編譯:

import SampleApp._ 
import spray.json._ 

class SampleApp { 
    import MyJsonProtocol._ 
    val inputJson = """{"children":["a", "b", "c"]}""" 
    println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}") 
} 

object SampleApp { 
    case class MyCaseClass(children: List[String]) 

    object MyJsonProtocol extends DefaultJsonProtocol { 
    //Explicit type added here now 
    implicit val myCaseClassSchemaFormat: JsonFormat[MyCaseClass] = jsonFormat1(MyCaseClass) 
    } 
} 

工作代碼#2 - 隱含內聯,推斷類型:

但是,將隱式參數放在使用它們的地方,沒有顯式類型,也有效!

import SampleApp._ 
import spray.json._ 

class SampleApp { 
    import DefaultJsonProtocol._ 

    //Now in-line custom JsonFormat rather than imported 
    implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass) 

    val inputJson = """{"children":["a", "b", "c"]}""" 
    println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}") 
} 

object SampleApp { 
    case class MyCaseClass(children: List[String]) 
} 
+0

這是其中一個「當我這樣做時會感到痛苦」的問題,其中最好的答案几乎肯定是「不要那麼做」。以我的經驗,缺乏類型註釋的隱式值是Scala中最常見的混淆源,行爲中奇怪的跨版本差異等。 –

+0

嗨特拉維斯 - 確實,這是一個有趣的錯誤工作,但我想下一次類型註釋將成爲我的第一個類似的問題呼叫端口!不知道這是否算作Scala bug,但可能會把某些東西放到郵件列表中,以防萬一。 – MrProper

+1

編譯器吐出一條錯誤消息,說'隱式方法不適用於此,因爲它是在應用程序點之後出現的,它缺少顯式結果類型,所以至少該錯誤對於診斷和修復來說是微不足道的。「 – Hugh

回答

3

尋找休在他的評論中提到的錯誤消息後,我能找到2010這個StackOverflow的問題:Why does this explicit call of a Scala method allow it to be implicitly resolved?

這使我在2008年創造了這個斯卡拉問題,並於2011年關閉:https://issues.scala-lang.org/browse/SI-801(「?需要隱式轉換明確的結果類型」)

馬丁說:

我實現了一個稍微每未知規則:沒有顯式結果類型的隱式轉換僅在自定義後的文本中可見。這樣,我們避免了循環引用錯誤。我現在關閉,看看它是如何工作的。如果我們仍然有問題,我們會回到這個問題。

這適用 - 如果我重新排序斷裂代碼,以便同伴對象被聲明第一,那麼代碼編譯。(這有點奇怪!)

(我懷疑我沒有看到'隱式方法在這裏不適用'消息,因爲我有一個隱含的值而不是轉換 - 雖然我在這裏假設根本原因是相同的以上)。

相關問題