Scala Circe:将隐式编码器移动到泛型类中

Scala Circe:将隐式编码器移动到泛型类中,scala,generics,types,shapeless,circe,Scala,Generics,Types,Shapeless,Circe,我在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

我在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")))
}
下面是一个极好的答案:,我现在尝试一个示例,在这个示例中,我可以将编码器构建到一个类中

但是,当我运行上述代码时,它会显示:

找不到参数编码器的隐式值: 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")))
所以我的问题是,如何将隐式定义的编码器放入类的作用域中。任何解释该理论的答案都将不胜感激

编辑:使用伊万的结构,它的作品

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)))
}
现在我的问题是,为什么会发生这种情况。当我移动定义时 类中的隐式编码器,为什么编译器不能 拿起它怎么用

答案是在class
myClass
的范围内没有隐式的
Encoder[T]

您可以通过将
(隐式编码器:编码器[T])
移动到构造函数来修复它,您已经这样做了

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

class myClass[T]

您应该在
myClass

找不到参数编码器的隐式值: 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")))
这是由于缺少泛型类型的问题造成的。创建
myClass
的新实例时,您没有指定类型
t
。如果你这样做,它将被编译

比如说,

val name = new myClass[Int](Some(Name("Noob")))
这将在运行时在seqToJson(data.get)行失败,因为您没有传递任何
数据

如何将隐式定义的编码器放入 班级


构造函数是一个很好的选择

考虑下面的简化代码段

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
我们实际上请求编码器[无任何内容]
哪些错误。事实上,您可以通过简单地请求来模拟类似的错误

implicitly[Encoder[Nothing]]

有哪些错误

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

不知道为什么它特别提到了
encodeZoneOffset
,但它可能与隐式搜索的工作方式有关,
encodeZoneOffset
Encoder
companion中的隐式值。

谢谢Ivan,我添加了一个编辑,试图对您所说的内容进行编码。由于某种原因,编译再次失败。有办法解决吗?您没有从
def seqToJson[t]
中删除
t
。我的回答中提到了这一点,我现在明白了,多亏了Ivan,它起作用了——看起来Scala需要花很多时间才能解决我的一个问题:是否可以使用Any类型,而不是泛型类型T?在这种情况下它不会编译,但我相信一定有办法解决这个问题,我不完全确定您想要实现什么。当使用隐式
Encoder[T]
时,编译器必须事先知道类型
T
,以便从隐式上下文中选择正确的编码器。如果你说
Any
,就会引起歧义。