如何在函数内使用Circe将Seq转换为Json-不断获取“未找到隐式值"错误 [英] How to Convert Seq to Json using Circe inside a function - keep getting "implicit value not found" error

查看:111
本文介绍了如何在函数内使用Circe将Seq转换为Json-不断获取“未找到隐式值"错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为工作中的项目学习Circe和Scala.为了说明我的问题,请从以下示例开始:

I am learning Circe and Scala for a project at work. To explain my issue, start with the following example:

import io.circe.syntax._

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

好,因此输出:

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

这很好.

现在,我想使我的代码更通用.我想编写一个接受Sequence的函数,其元素可以是AnyVal类型.

Now I want to make my code a bit more general. I want to write a function that takes in a Sequence, whose elements can be of type 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:

Ok so I need to make an implicit value for the encoder because the type T is too general. Here is my second attempt using 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))
}

此操作失败,并显示以下信息:

This fails with:

type mismatch;
found   : Seq[String]
required: Seq[T]

我该如何解决这个问题?我通读了Circe文档,但无法理解如何处理此类示例.

How do I go about solving this? I read through the Circe docs but I cannot understand how to handle this type of example.

如果有人能对他们如何解决这样的问题进行一些解释,请多多关照,将不胜感激.我应该补充说我是Scala的新手,所以任何解释也可以用来解释该理论.

If someone could kindly explain, with a bit of explanation as to how they resolve something like this, it would be much appreciated. I should add I am new to Scala so any explanation would be useful which explains the theory too.

谢谢!

推荐答案

Circe建立在类型类模式上,其Encoder是它提供的类型类之一.关键思想是,您不需要(并提供)需要编码的任何特定类型的类型类实例,而不是使用运行时反射之类的方法来找出如何编码任意值的方法.

Circe is built on the type class pattern, and its Encoder is one of the type classes it provides. The key idea is that instead of using something like runtime reflection to figure out how to encode some arbitrary value, you require (and provide) a type class instance for any particular type you need to encode.

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

If you're working with a concrete type, the compiler will tell you whether you have a type class instance in scope or not. List("a", "b").asJson will compile, for example, while List(1, "a").asJson (where the inferred type is List[Any]) won't. This is because Circe provides an implicit Encoder[List[String]], but not an implicit Encoder[List[Any]].

如果要使用泛型类型,则需要类型类约束.在您的情况下,看起来像这样:

If you're working with a generic type, you need a type class constraint. In your case that'd look like this:

def f1[T: Encoder](lst: Seq[T]): Json = {
  lst.asJson
}

哪个是类似于thi的语法糖:

Which is syntactic sugar for something similar to thi:

def f1[T](lst: Seq[T])(implicit encodeT: Encoder[T]): Json = {
  lst.asJson
}

您需要在呼叫链中包含此约束.

You'll need to include this constraint up through the call chain.

作为脚注,在引用shapeless标记时,值得注意的是,类型类模式与泛型派生的思想是分开的,后者通常在Scala中使用Shapeless进行.编写import io.circe.generic.auto._时,这是将EncoderDecoder类型类实例放入案例类范围的一种方法.但是,您不必不需要泛型派生-这只是使用编译时反射来定义类型类实例的一种便捷方法.无论您使用通用派生还是手动编写实例,以上所有信息都是完全相同的.

As a footnote, in reference to the shapeless tag, it's worth noting that the type class pattern is separate from the idea of generic derivation, which is often done in Scala with Shapeless. When you write import io.circe.generic.auto._, that's one way of putting Encoder and Decoder type class instances into scope for case classes. But you never need generic derivation—it's just one convenient way of defining type class instances using compile-time reflection. All of the information above is exactly the same whether you use generic derivation or manually-written instances.

这篇关于如何在函数内使用Circe将Seq转换为Json-不断获取“未找到隐式值"错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆