如何在函数内使用 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._
时,这是将 Encoder
和 Decoder
类型 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
我正在为一个工作项目学习 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._
时,这是将 Encoder
和 Decoder
类型 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