2016-04-02 88 views
7

的序列不知道這是一個錯誤,但在最後的情況下,下面的演示失敗:噴霧JSON失敗的Eithers

import spray.json._ 
import DefaultJsonProtocol._ 

object SprayTest { 
    1.toJson 
    "".toJson 
    (Left(1): Either[Int, String]).toJson 
    (Right(""): Either[Int, String]).toJson 
    Seq(1).toJson 
    Seq("").toJson 
    Seq(Left(1), Right("")).toJson 
    Seq(Left(1), Right("")).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat))) 
} 

因此,所有的積木似乎工作,但格式的組成爲SeqEither失敗,即使我嘗試用勺子餵它。

我看到以下錯誤:

[error] SprayTest.scala:11: Cannot find JsonWriter or JsonFormat type class for Seq[Product with Serializable with scala.util.Either[Int,String]] 
[error] Seq(Left(1), Right("")).toJson 
[error]       ^
[error] SprayTest.scala:12: type mismatch; 
[error] found : spray.json.DefaultJsonProtocol.JF[Either[Int,String]] 
[error]  (which expands to) spray.json.JsonFormat[Either[Int,String]] 
[error] required: spray.json.JsonFormat[Product with Serializable with scala.util.Either[Int,String]] 
[error] Note: Either[Int,String] >: Product with Serializable with scala.util.Either[Int,String] (and spray.json.DefaultJsonProtocol.JF[Either[Int,String]] <: spray.json.JsonFormat[Either[Int,String]]), but trait JsonFormat is invariant in type T. 
[error] You may wish to define T as -T instead. (SLS 4.5) 
[error] Seq(Left(1), Right("")).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat))) 

任何想法怎麼辦?

回答

14

這是一個約Either -the LeftRight構造最討厭的東西都擴展ProductSerializable,但Either本身並沒有,這會導致可怕的推斷類型之一:

scala> Seq(Left(1), Right("")) 
res0: Seq[Product with Serializable with scala.util.Either[Int,String]] = List(Left(1), Right()) 

因爲JsonFormat是在其類型參數中不變,事實上,您有一個A的實例並不意味着您有一個Product with Serializable with A的實例。具體來說,實際上有一個Either[Int, String]的實例,但推斷類型中的額外垃圾意味着編譯器找不到它。

scala> Seq(Left(1), Left(2)).toJson 
<console>:18: error: Cannot find JsonWriter or JsonFormat type class for Seq[scala.util.Left[Int,Nothing]] 
     Seq(Left(1), Left(2)).toJson 
          ^

可以通過提供一個類型,而不是使用推斷一個解決這兩個問題:

scala> val xs: Seq[Either[Int, String]] = Seq(Left(1), Right("")) 
xs: Seq[Either[Int,String]] = List(Left(1), Right()) 

scala> xs.toJson 
res1: spray.json.JsValue = [1,""] 

如果你沒有序列中的Right

類似的事情發生在很多情況下,這不是問題,因爲您經常會從顯式返回Either而不是直接使用LeftRight的方法中獲取值Either導致這個問題。

作爲一個腳註:這就是爲什麼當你定義自己的ADT時,你應該始終將根密封特徵(或密封類)擴展爲Product with Serializable。如果標準的圖書館設計師遵循了這個建議,我們都會變得更好。

+0

這修復了我的例子,但不幸的是,它不能修復我的真實代碼:(但非常豐富,謝謝! – acjay

2

我覺得如果你添加一個類型推諉的說理的Seqs的元素它會編譯:

Seq(Left(1): Either[Int, String], Right(""): Either[Int, String]).toJson 
Seq(Left(1): Either[Int, String], Right(""): Either[Int, String]).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat)) 

你也可以給它一個單一類型歸屬:

(Seq(Left(1), Right("")): Either[Int, String]).toJson 
(Seq(Left(1), Right("")): Either[Int, String]).toJson(seqFormat(eitherFormat(IntJsonFormat, StringJsonFormat)) 

我覺得問題是scalac試圖確定你提供給Seq的元素之間的共同最小上界,以派生一個單一的類型(因爲標準集合需要它們元素的同類數據類型),並且它不會推斷出你想要的是什麼幫幫我。如果scala標準庫已經添加了使用Serializable擴展Product到抽象類兩種定義,你不需要這樣做,但是因爲Right和Left兩個子類都是case類(隱含地擴展了Product和Serializable),所以它們包含在推斷的類型中,這會導致您使用噴霧所需的不變類型的問題。

+0

看起來像特拉維斯擊敗了我。 :-) –