我正在为工作中的一个项目学习Circe和Scala。为了解释我的问题,从下面的例子开始。
import io.circe.syntax._
object TestDrive extends App {
val labels = Seq("Banana", "Banano", "Grapefruit")
println(labels.asJson)
}
好吧,所以这个输出。
["Banana","Banano","Grapefruit"]
这很好.
现在我想让我的代码更通用一点。我想写一个函数,接收一个Sequence,其元素可以是AnyVal类型。
这是我的尝试。
import io.circe.syntax._
import io.circe.Json
object TestDrive extends App {
def f1[T](lst: Seq[T]): Json = {
lst.asJson
}
val labels = Seq("Banana", "Banano", "Grapefruit")
println(f1(labels))
}
失败的原因是:
could not find implicit value for parameter encoder: io.circe.Encoder[Seq[T]]
好吧,所以我需要为编码器做一个隐式值 因为T的类型太泛了。这是我使用scala ClassTags进行的第二次尝试。
import io.circe.syntax._
import io.circe.Json
import scala.reflect.ClassTag
object TestDrive extends App {
def f1[T <: AnyVal](lst: Seq[T])(implicit ev: ClassTag[T]): Json = {
lst.asJson
}
val labels = Seq("Banana", "Banano", "Grapefruit")
println(f1(labels))
}
失败的原因是:
type mismatch;
found : Seq[String]
required: Seq[T]
我如何解决这个问题?我阅读了Circe文档,但我不明白如何处理这种类型的例子。
如果有人能解释一下他们是如何解决这样的问题的,那将非常感激。我应该补充一下,我是Scala的新手,所以任何解释都会很有用,也能解释理论。
谢谢!我正在学习Circe和Scala。
Circe是建立在类型类模式上的,它的 Encoder
是它提供的类型类之一。关键的想法是,与其使用类似于运行时反射的东西来弄清楚如何对一些任意值进行编码,不如为你需要编码的任何特定类型要求(并提供)一个类型类实例。
如果你正在使用一个具体的类型,编译器会告诉你是否在范围内有一个类型类实例。List("a", "b").asJson
将会编译,例如,而 List(1, "a").asJson
(其中推断的类型是 List[Any]
)不会。这是因为Circe提供了一个隐式的 Encoder[List[String]]
但不是隐性的 Encoder[List[Any]]
.
如果你正在使用一个通用类型,你需要一个类型类约束。在你的例子中,它看起来像这样。
def f1[T: Encoder](lst: Seq[T]): Json = {
lst.asJson
}
这就是类似于 thi 的语法糖。
def f1[T](lst: Seq[T])(implicit encodeT: Encoder[T]): Json = {
lst.asJson
}
你需要在调用链中包含这个约束条件。
作为一个脚注,在提到 shapeless
标签,值得注意的是,类型类模式与 一般推导在Scala中经常用Shapeless来完成。当你写 import io.circe.generic.auto._
这就是一种说法 Encoder
和 Decoder
型类实例进入case类的范围。但你从来没有 需要 通用派生--这只是使用编译时反射定义类型类实例的一种方便的方式。无论你是使用通用派生还是手动编写实例,上面的所有信息都是完全一样的。
import io.circe._
import io.circe.syntax._
import io.circe.Json
object TestDrive extends App {
def f1[T](lst: Seq[T])(implicit encoder: Encoder[T]): Json = {
lst.asJson
}
val labels = Seq("Banana", "Banano", "Grapefruit")
println(f1(labels))
val intLabels = Seq(1,2,3)
println(f1(intLabels))
}
你基本上需要提供编码器来实现。默认情况下,circe-core会负责处理scala通用类型(如集合、选项和普通类型)的json创建。如果你需要特定的case类,你仍然可以使用 circe-generic
.
Circe通过使用Shapeless实现自动推导。https:/circe.github.iocircecodecsauto-derivation.html。