繁体   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