如何在函数内使用 Circe 将 Seq 转换为 Json - 不断出现 "implicit value not found" 错误

How to Convert Seq to Json using Circe inside a function - keep getting "implicit value not found" error

我正在为一个工作项目学习 Circe 和 Scala。为了解释我的问题,请从以下示例开始:

import io.circe.syntax._

object TestDrive extends App {
  val labels = Seq("Banana", "Banano", "Grapefruit")
  println(labels.asJson)
}

好的,所以输出:

["Banana","Banano","Grapefruit"]

这很好。

现在我想让我的代码更通用一些。我想写一个接受序列的函数,序列的元素可以是 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 建立在类型 class 模式之上,其 Encoder 是它提供的类型 classes 之一。关键思想是,不是使用运行时反射之类的东西来弄清楚如何编码任意值,而是需要(并提供)一个类型 class 实例,用于需要编码的任何特定类型。

如果您正在使用具体类型,编译器会告诉您范围内是否有类型 class 实例。例如,List("a", "b").asJson 将编译,而 List(1, "a").asJson(推断类型为 List[Any])则不会。这是因为 Circe 提供了一个隐式的 Encoder[List[String]],而不是一个隐式的 Encoder[List[Any]].

如果您使用的是通用类型,则需要类型 class 约束。在你的情况下,它看起来像这样:

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 标签时,值得注意的是类型 class 模式与 泛型派生 的想法是分开的,这通常在 Scala 中使用 Shapeless 完成。当您编写 import io.circe.generic.auto._ 时,这是将 EncoderDecoder 类型 class 实例放入 case classes 范围的一种方式。但是您永远 不需要 泛型派生 — 它只是使用编译时反射定义类型 class 实例的一种便捷方式。以上所有信息,不管你是泛型推导还是手写实例,都是完全一样的。

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 将负责处理 json scala 通用类型(如集合、选项和普通类型)的创建。如果您需要特定案例 class,您仍然可以使用 circe-generic.

Circe使用Shapeless实现了自动推导。 https://circe.github.io/circe/codecs/auto-derivation.html