隐式编码器 将隐式编码器移入通用类中

问题描述 投票:0回答:1

我是用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")))
}

继这里的出色回答之后 链接我现在正在尝试一个例子,在这个例子中,我可以在一个类中建立一个编码器。

然而,当我运行上面的代码时,它说:"无法找到参数encoder的隐式值:io.circe.Encoder[T][错误]val mydata::"。

无法找到参数 encoder 的隐式值:io.circe.Encoder[T] [error] val mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) [error] ^mydata.Json = seqToJson(data.get) 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")))

所以我的问题是,如何让隐式定义的编码器进入Class的范围。如果有任何理论解释的答案,将非常感激!

EDIT:用了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个回答
3
投票

现在我的问题是,为什么会发生这种情况。当我把隐式编码器的定义移到类里面时,为什么编译器不能接收到如何使用它?

答案是没有隐式的 Encoder[T] 属于课的范围 myClass.

你可以通过移动来解决它 (implicit encoder: Encoder[T]) 到构造器,你做到了。

此外,你还定义了通用类型 T 两处

class myClass[T]

def seqToJson[T]

你应该只保留一个在 myClass

找不到参数 encoder 的隐式值:io.circe.Encoder[Seq[T]] 含糊不清的隐式值。

这是由于缺少通用类型的问题造成的。你没有指定类型 T 当创建一个新的 myClass. 如果你这样做,它会编译。

例如:

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

这将在运行时失败,在行 seqToJson(data.get) 因为你没有通过任何 data.

我怎样才能让隐式定义的编码器进入类的作用域?

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


1
投票

考虑以下简化的片段

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 但这可能与隐式搜索的工作原理和 encodeZoneOffset最后的 隐含价值 Encoder 伴侣。

© www.soinside.com 2019 - 2024. All rights reserved.