2015-09-07 10 views
8

私は、parseJsonメソッドを使用してスプレーjsonを使用していくつかのJSONをケースクラスにデシリアライズするコードを用意しています。implicを解決する際にScalaはどのように明示的な型を使用しますか?

暗黙的な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) 
    } 
} 

結果:同じことが暗黙のmyCaseClassSchemaFormatの明示的なインポートで発生することを

Cannot find JsonReader or JsonFormat type class for SampleAppObject.MyCaseClass 

注意。

ワーキングコード#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

これは、「これを行うと痛い」という質問の1つです。これは、最良の答えが「確かにそうしない」ということです。私の経験では、型の注釈を持たない暗黙的な値は、Scalaにおける混乱の最も一般的な原因の1つ、動作の奇妙なクロスバージョンの違いなどです。 –

+0

こんにちはトラビス - 確かに、これは回避するには面白いバグでしたが、次回のタイプの注釈は私の最初の似たような問題の呼びかけになるでしょう! Scalaのバグとしてカウントされるかどうかは分かりませんが、メーリングリストに何かを載せたり、場合によっては問題を提起してください。 – MrProper

+1

コンパイラは、 'アプリケーションポイントの後に来るため明示的な結果の型がないため、暗黙のメソッドはここには適用されません。'というエラーメッセージを出すので、少なくともエラーの診断と修正は簡単です。 – Hugh

答えて

3

ヒューは彼のコメントに記載されたエラーメッセージを検索した後、私は2010年からこのStackOverflowの質問を見つけることができたが:Why does this explicit call of a Scala method allow it to be implicitly resolved?

は、これが2008年に作成されたこのScalaの問題に私を導いた、そして2011年に閉鎖さ:https://issues.scala-lang.org/browse/SI-801(「暗黙的な変換のための明示的な結果の型を必要とする?」)

マーティンは、次のように述べています

を私はあたりもう少しを実装していますミッシェルルール:明示的な結果タイプのない暗黙的な変換は、それ自身の定義に従うテキストでのみ表示されます。このようにして、循環参照エラーを回避します。私は今、これがどう機能するかを見るために閉じます。私たちがまだ問題を抱えていれば、私たちは移住してこれに戻ります。

これが保持している - 私があれば再オーダー破壊コードをコンパニオンオブジェクトは、コードをコンパイルし、最初を宣言されているように。(まだ少し変です!)

の暗黙のメソッドはここには適用されないと思われます。メッセージです。変換ではなく暗黙的な値があるためです。根本的な原因は上記)。

関連する問題