json - 喷雾 json 对双子的 Seq 失败

标签 json scala covariance spray-json

不确定这是一个错误,但以下演示在最终情况下失败:

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 最烦人的事情之一——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直接导致这个问题的方式。

作为脚注:这就是为什么你应该总是让你的根密封特征(或密封类)扩展 Product with Serializable当您定义自己的 ADT 时。如果标准库设计者遵循了这个建议,我们都会过得更好。

关于json - 喷雾 json 对双子的 Seq 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36378223/

相关文章:

scala - 为什么 Scala 中的 groupBy 会改变列表项的顺序?

java - 如何使协变 Consumer<?扩展基地>工作?

java - Java 是否有任何计划添加泛型集合协变性?

json - boolean 值可以/应该用引号在 json 中传递吗?

python - 在python中打印json文件的所有键

Scala 和 mockito 测试 twilio MessageFactory.create() 方法

c# - Casting List<T> - 协方差/逆变问题

javascript - 按一次迭代后停止的日期值对 JSON 数组进行排序

javascript - 将值推送到数组末尾添加未定义

scala - 安装akka(scala和ubuntu)的困难