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)))
}
所以所有的构建块似乎都有效,但是 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
最烦人的事情之一——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,""]
在许多情况下,这不是问题,因为您通常会从显式 return 和 Either
而不是使用 [=14= 的方法中获取 Either
值] 和 Right
直接导致此问题的方式。
作为脚注:这就是为什么您在定义自己的 ADT 时应该始终将根密封特征(或密封 class)扩展 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 标准库已将 extends Product with Serializable 添加到抽象 class Either 定义中,则您不需要执行此操作,但由于子类型 Right 和 Left 都是 case classes(隐式执行扩展 Product 和 Serializable),它们被包含在推断类型中,这导致您遇到喷雾所需的不变类型问题。
不确定这是一个错误,但以下演示在最终情况下失败了:
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
最烦人的事情之一——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,""]
在许多情况下,这不是问题,因为您通常会从显式 return 和 Either
而不是使用 [=14= 的方法中获取 Either
值] 和 Right
直接导致此问题的方式。
作为脚注:这就是为什么您在定义自己的 ADT 时应该始终将根密封特征(或密封 class)扩展 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 标准库已将 extends Product with Serializable 添加到抽象 class Either 定义中,则您不需要执行此操作,但由于子类型 Right 和 Left 都是 case classes(隐式执行扩展 Product 和 Serializable),它们被包含在推断类型中,这导致您遇到喷雾所需的不变类型问题。