[英]spray-json failing for Seq of 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)))
}
因此所有構建塊似乎都有效,但是Seq
和Either
格式的組合都失敗了,即使我嘗試用勺子喂它。
我看到以下錯誤:
[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)))
知道是什么給出的嗎?
這是關於最討厭的事情之一Either
-the Left
和Right
的構造都延伸Product
和Serializable
,但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]
的實例,但推斷類型中的額外垃圾意味着編譯器無法找到它。
如果序列中沒有Right
,則會發生類似的事情:
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,""]
在許多情況下,這不是問題,因為您經常會從顯式返回Either
方法中獲取您的Either
值,而不是直接以導致此問題的方式使用Left
和Right
。
作為腳注:這就是為什么在定義自己的ADT時,應始終使用root密封特性(或密封類)擴展Product with Serializable
。 如果標准圖書館設計師遵循這一建議,我們會好得多。
我想如果你將類型歸屬添加到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標准庫已將擴展Product with Serializable添加到抽象類中,則無需執行此任何定義,但由於子類型Right和Left都是case類(隱式地擴展Product和Serializable),因此它們包括在內在推斷類型中,這會導致噴塗所需的不變類型出現問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.