簡體   English   中英

spray-json因為Eithers的Seq而失敗了

[英]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)))
}

因此所有構建塊似乎都有效,但是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)))

知道是什么給出的嗎?

這是關於最討厭的事情之一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]的實例,但推斷類型中的額外垃圾意味着編譯器無法找到它。

如果序列中沒有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值,而不是直接以導致此問題的方式使用LeftRight

作為腳注:這就是為什么在定義自己的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM