【问题标题】:Circe: Moving an Implicit Encoder into A Generic ClassCirce:将隐式编码器移动到泛型类中
【发布时间】:2020-09-30 04:38:00
【问题描述】:

我正在与 Circe 图书馆合作,并想学习其中的技巧。考虑以下代码:

import io.circe.generic.auto._
import io.circe.syntax._
import io.circe.{Decoder, Encoder, Json}

sealed trait Something
case class Name(val name: String) extends Something

class myClass[T](name: Option[Name] = None, data: Option[Seq[T]] = None) {
  // convert an arbitrary sequence to json
  def seqToJson[T](lst: Seq[T])(implicit encoder: Encoder[T]): Json = {
    lst.asJson
  }

  val mydata: Json = seqToJson(data.get)
}

object Trace extends App {
  val name = new myClass(Some(Name("Noob")))
}

从这里的优秀答案开始:Link,我现在正在尝试一个可以将编码器构建到类中的示例。

但是当我运行上面的代码时,它说:

找不到参数编码器的隐含值: io.circe.Encoder[T] [error] val mydata: Json = seqToJson(data.get) [错误] ^

现在我的问题是,为什么会这样。当我把隐式编码器的定义移到类里面的时候,为什么编译器不知道怎么用呢?

我也尝试了其他方法,即移动到我定义隐式编码器的位置:

import io.circe.generic.auto._
import io.circe.syntax._
import io.circe.{Decoder, Encoder, Json}

sealed trait Something
case class Name(val name: String) extends Something

class myClass[T](name: Option[Name] = None, data: Option[Seq[T]] = None)(implicit encoder: Encoder[T]) {
  // convert an arbitrary sequence to json
  def seqToJson[T](lst: Seq[T]): Json = {
    lst.asJson
  }

  val mydata: Json = seqToJson(data.get)
}

object Trace extends App {
  val name = new myClass(Some(Name("Noob")))
}

这会产生以下错误:

找不到参数编码器的隐含值:io.circe.Encoder[Seq[T]] 模棱两可的隐含值​​:

[error]  both lazy value encodeDuration in object Encoder of type io.circe.Encoder[java.time.Duration]
[error]  and lazy value encodeInstant in object Encoder of type io.circe.Encoder[java.time.Instant]
[error]  match expected type io.circe.Encoder[T]
[error] Error occurred in an application involving default arguments.
[error]   val name = new myClass(Some(Name("Noob")))

所以我的问题是,如何将隐式定义的编码器纳入类的范围。任何解释理论的答案将不胜感激!

编辑:使用了 Ivan 的结构,并且有效!

import io.circe.syntax._
import io.circe.{Decoder, Encoder, Json}

class myClass[T](data: Seq[T])(implicit encoder: Encoder[T]) {
  def seqToJson(lst: Seq[T]): Json = {
    lst.asJson
  }
}

object Trace extends App {
  println(new myClass[Int](data = Seq(1,2,3)))
}

【问题讨论】:

    标签: scala generics types shapeless circe


    【解决方案1】:

    现在我的问题是,为什么会这样。当我移动定义时 类内部的隐式编码器,为什么编译器不能 看看怎么用?

    答案是在myClass 类的范围内不存在隐含的Encoder[T]

    您可以通过将 (implicit encoder: Encoder[T]) 移动到构造函数来修复它,您已经这样做了。

    此外,您在两个地方定义泛型类型T

    class myClass[T]
    

    def seqToJson[T]
    

    你应该只保留一个myClass

    找不到参数编码器的隐含值: io.circe.Encoder[Seq[T]] 模糊隐含值:

    这是由于缺少泛型类型的问题造成的。在创建 myClass 的新实例时,您没有指定类型 T。如果你这样做,它将编译。

    例如,

    val name = new myClass[Int](Some(Name("Noob")))
    

    这将在运行时在线 seqToJson(data.get) 上失败,因为您没有传入任何 data

    如何将隐式定义的编码器纳入范围 类

    构造函数是一个不错的选择

    【讨论】:

    • 感谢 Ivan,我添加了一个编辑,我尝试编写我对您所说内容的解释。由于某种原因,编译再次失败。有办法解决吗?
    • 您没有从def seqToJson[T] 中删除T。我的回答中提到了
    • 啊,我现在明白了,感谢 Ivan,它可以工作了 - 看起来 Scala 需要花很多时间才能掌握窍门
    • 我有一个问题是是否可以使用 Any 类型,而不是泛型类型 T?在这种情况下它不会编译,但我相信一定有办法解决这个问题
    • 我不完全确定你想要实现什么。使用隐式Encoder[T] 时,编译器必须提前知道T 类型,以便它可以从隐式上下文中选择正确的编码器。如果你说Any,就会产生歧义。
    【解决方案2】:

    考虑以下简化的 sn-p

    def f[T](v: Option[T] = None) = v
    f() // T is inferred as Nothing
    

    这里的类型参数T被推断为Nothing,因为None被定义为

    case object None extends Option[Nothing]
    

    因此在以下情况下

    def f[T](v: Option[T] = None)(implicit ev: Encoder[T]) = v
    f() // error because requiring Encoder[Nothing] capability
    

    我们实际上请求Encoder[Nothing] 哪些错误。其实你可以通过简单的请求来模拟类似的错误

    implicitly[Encoder[Nothing]]
    
    

    哪些错误

    Error: diverging implicit expansion for type io.circe.Encoder[Nothing]
    starting with lazy value encodeZoneOffset in object Encoder
    

    不知道为什么特别提到encodeZoneOffset,但这可能与隐式搜索的工作原理有关,而encodeZoneOffsetEncoder 伴侣中的last 隐式值。

    【讨论】:

      猜你喜欢
      • 2017-08-25
      • 2017-11-27
      • 1970-01-01
      • 2019-01-26
      • 2017-05-02
      • 2023-03-10
      • 2023-03-12
      • 2020-10-12
      • 1970-01-01
      相关资源
      最近更新 更多