gpt4 book ai didi

json - 为基本特征具有(密封)类型成员的密封案例类族派生circe Codec

转载 作者:行者123 更新时间:2023-12-04 12:52:44 26 4
gpt4 key购买 nike

我可以很容易地为这样的密封案例类族一般派生一个编解码器:

import io.circe._
import io.circe.generic.auto._

sealed trait Base
case class X(x: Int) extends Base
case class Y(y: Int) extends Base

object Test extends App {
val encoded = Encoder[Base].apply(Y(1))
val decoded = Decoder[Base].apply(encoded.hcursor)
println(decoded) // Right(Y(1))
}

但是,如果我向基类添加一个类型成员,我就不能再这样做了,即使它受到密封特征的限制:
import io.circe._
import io.circe.generic.auto._

sealed trait Inner
case class I1(i: Int) extends Inner
case class I2(s: String) extends Inner

sealed trait Base { type T <: Inner }
case class X[S <: Inner](x: S) extends Base { final type T = S }
case class Y[S <: Inner](y: S) extends Base { final type T = S }

object Test extends App {
val encodedInner = Encoder[Inner].apply(I1(1))
val decodedInner = Decoder[Inner].apply(encodedInner.hcursor) // Ok
println(decodedInner) // Right(I1(1))

// Doesn't work: could not find implicit for Encoder[Base] etc
// val encoded = Encoder[Base].apply(Y(I1(1)))
// val decoded = Decoder[Base].apply(encoded.hcursor)
// println(decoded)
}

有没有办法实现我想要的?如果没有,我可以改变什么来获得类似的东西?

最佳答案

这不起作用的主要原因是因为你试图从本质上做

Encoder[Base { type T }]

不用说是什么类型 T是。这类似于期望这个函数编译 -
def foo[A] = implicitly[Encoder[List[A]]]

您需要明确地优化您的类型。

解决此问题的一种方法是使用 Aux图案。您不能使用典型的 type Aux[S] = Base { type T = S }因为在尝试派生实例时不会给您副产品( XY 类不能从类型别名扩展)。相反,我们可以通过创建另一个密封特征作为 Aux 来绕过它。并让我们的案例类从那里扩展。

只要您的所有案例类都从 Base.Aux 扩展而不是直接来自 Base ,您可以使用以下滥用 .asInstanceOf安抚类型系统。
sealed trait Inner
case class I1(i: Int) extends Inner
case class I2(s: String) extends Inner

sealed trait Base { type T <: Inner }
object Base {
sealed trait Aux[S <: Inner] extends Base { type T = S }
implicit val encoder: Encoder[Base] = {
semiauto.deriveEncoder[Base.Aux[Inner]].asInstanceOf[Encoder[Base]]
}
implicit val decoder: Decoder[Base] = {
semiauto.deriveDecoder[Base.Aux[Inner]].asInstanceOf[Decoder[Base]]
}
}

val encoded = Encoder[Base].apply(Y(I1(1)))
val decoded = Decoder[Base].apply(encoded.hcursor)

请注意,这在很大程度上取决于您实际使用类型的方式。我想你不会依赖调用 Encoder[Base]直接使用 import io.circe.syntax._并调用 .asJson扩展方法。在这种情况下,您可以依赖 Encoder[Base.Aux[S]]将根据正在编码/解码的值推断出的实例。对于您的用例,类似以下的内容可能就足够了,而无需诉诸 .asInstanceOf黑客。
implicit def encoder[S <: Inner : Encoder]: Encoder[Base.Aux[S]] = {
semiauto.deriveEncoder
}

同样,这完全取决于您如何使用实例。我怀疑您是否真的需要 Base 中的类型成员,如果你把它移到一个通用参数中,事情会更简单,这样派生者就可以为你找出副产品。

关于json - 为基本特征具有(密封)类型成员的密封案例类族派生circe Codec,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36843532/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com