gpt4 book ai didi

json - Circe:高效解码多级ADT

转载 作者:行者123 更新时间:2023-12-01 01:53:38 25 4
gpt4 key购买 nike

我想用 Circe 解码以下 ADT:

sealed trait PaymentType
object PaymentType extends EnumEncoder[PaymentType] {
case object DebitCard extends PaymentType
case object Check extends PaymentType
case object Cash extends PaymentType
case object Mobile extends PaymentType
}
sealed trait CreditCard extends PaymentType
object CreditCard extends EnumEncoder[CreditCard] {
case object UNKNOWN_CREDIT_CARD extends CreditCard
case object NOT_ACCEPTED extends CreditCard
case object VISA extends CreditCard
case object MASTER_CARD extends CreditCard
case object DINERS_CLUB extends CreditCard
case object AMERICAN_EXPRESS extends CreditCard
case object DISCOVER_CARD extends CreditCard
}

如您所见,有一个父类型 PaymentType ,其中有一些直接继承人和另一个密封性状家族 CreditCard .现在解码是这样完成的:
object CreditCard {
implicit val decoder: Decoder[CreditCard] = Decoder.instance[CreditCard] {
_.as[String].map {
case "NOT_ACCEPTED" => NOT_ACCEPTED
case "VISA" => VISA
case "MASTER_CARD" => MASTER_CARD
case "DINERS_CLUB" => DINERS_CLUB
case "AMERICAN_EXPRESS" => AMERICAN_EXPRESS
case "DISCOVER_CARD" => DISCOVER_CARD
case _ => UNKNOWN_CREDIT_CARD
}
}

object PaymentType {
implicit val decoder: Decoder[PaymentType] = Decoder.instance[PaymentType] {
_.as[String].flatMap {
case "DebitCard" => Right(DebitCard)
case "Check" => Right(Check)
case "Cash" => Right(Cash)
case "Mobile" => Right(Mobile)
case _ => Left(DecodingFailure("", List()))
}
}.or(CreditCard.decoder.widen)
}

我不喜欢的是 PaymentType解码器,特别是我需要创建一个额外的和不必要的实例 DecodingFailure在完全正常的情况下,当遇到基于信用卡的支付类型时。我们已经将 99.9% 的 CPU 花在了 JSON 处理上,只是看起来不太对劲。要么是糟糕的 ADT 设计,要么 Circe 应该有办法更好地处理这个问题。有任何想法吗?

最佳答案

您可以将回退移至 CreditCard解码器进入PaymentType解码器案例,可让您避免失败:

implicit val decoder: Decoder[PaymentType] = Decoder.instance[PaymentType] { c =>
c.as[String].flatMap {
case "DebitCard" => Right(DebitCard)
case "Check" => Right(Check)
case "Cash" => Right(Cash)
case "Mobile" => Right(Mobile)
case _ => CreditCard.decoder(c)
}
}

不过,在这种情况下,我可能会将字符串解析为单独的方法:
sealed trait PaymentType
object PaymentType extends EnumEncoder[PaymentType] {
case object DebitCard extends PaymentType
case object Check extends PaymentType
case object Cash extends PaymentType
case object Mobile extends PaymentType

private val nameMapping = List(DebitCard, Check, Cash, Mobile).map(pt =>
pt.productPrefix -> pt
).toMap

def fromString(input: String): Option[PaymentType] = nameMapping.get(input)
}

sealed trait CreditCard extends PaymentType
object CreditCard extends EnumEncoder[CreditCard] {
case object UNKNOWN_CREDIT_CARD extends CreditCard
case object NOT_ACCEPTED extends CreditCard
case object VISA extends CreditCard
case object MASTER_CARD extends CreditCard
case object DINERS_CLUB extends CreditCard
case object AMERICAN_EXPRESS extends CreditCard
case object DISCOVER_CARD extends CreditCard

private val nameMapping = List(
NOT_ACCEPTED,
VISA,
MASTER_CARD,
DINERS_CLUB,
AMERICAN_EXPRESS,
DISCOVER_CARD
).map(pt => pt.productPrefix -> pt).toMap

def fromString(input: String): CreditCard =
nameMapping.getOrElse(input, UNKNOWN_CREDIT_CARD)
}

然后你可以根据 fromString 编写解码器方法,这对我来说就像是解决问题的更好方法(在我的脑海中,我不确定哪种方法会涉及更少的分配)。不过,这可能主要是品味问题。

关于json - Circe:高效解码多级ADT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42300772/

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