组织与类型关联的Scala隐式

组织与类型关联的Scala隐式,scala,implicit,circe,quill.io,Scala,Implicit,Circe,Quill.io,我想介绍一些类型,以更大的类型表示字段的可能值。该字段需要能够对JSON进行编码/解码,也能够写入/读取数据库 我还是Scala新手,我想要的类型是sum type Status=NotVerified | Correct | error。因为我希望每个构造函数都有一个字符串表示,所以我创建了一个带有字符串参数的密封case类,然后创建了扩展该case类的对象。为了能够编码/解码,我还需要隐式,但我不确定如何构造它。我可以将它们放在对象内部的新对象中,如下所示: sealed case clas

我想介绍一些类型,以更大的类型表示字段的可能值。该字段需要能够对JSON进行编码/解码,也能够写入/读取数据库

我还是Scala新手,我想要的类型是sum type Status=NotVerified | Correct | error。因为我希望每个构造函数都有一个字符串表示,所以我创建了一个带有字符串参数的密封case类,然后创建了扩展该case类的对象。为了能够编码/解码,我还需要隐式,但我不确定如何构造它。我可以将它们放在对象内部的新对象中,如下所示:

sealed case class Status(name: String)
object Status {
  object NotVerified extends Status("not_verified")
  object Correct extends Status("correct")
  object Wrong extends Status("wrong")

  object implicits {
    implicit val encodeStatusJson: Encoder[Status] =
      _.name.asJson
    implicit val decodeStatusJson: Decoder[Status] =
      Decoder.decodeString.map(Status(_))

    implicit val encodeStatus: MappedEncoding[Status, String] =
      MappedEncoding[Status, String](_.name)

    implicit val decodeStatus: MappedEncoding[String, Status] =
      MappedEncoding[String, Status](Status(_))
  }
}
…然后在需要的地方显式导入这些,但这是非常…显式的

组织类型+隐式集合的好方法是什么?

如果添加应用方法,则可以从字符串创建适当的状态,这将使解码器正常工作。把地位抽象化

sealed abstract class Status(name: String)

object Status {
  object NotVerified extends Status("not_verified")
  object Correct extends Status("correct")
  object Wrong extends Status("wrong")

  def apply(name: String): Status = name match {
    case "not_verified" => NotVerified
    case "correct" => Correct
    case _ => Wrong
  }
}

我认为您现有的隐式仍然有效,但我不知道那些特定的库…

常用的方法是定义一个密封的特征:

或者是一个密封的抽象类,在当前的Scala版本中看起来可能更好:

sealed abstract class Status(val name: String)

object Status {
  case object NotVerified extends Status("not_verified")
  case object Correct extends Status("correct")
  case object Wrong extends Status("wrong")
}
为了避免导入隐式,可以将它们直接放置在类型的伴随对象中。有关更多详细信息,请参见问题,特别是类型的伴随对象一节

是的,为这样的枚举定义隐式很容易重复。您必须求助于反射或宏。我建议使用这个库,它还集成了Circe和Quill。 以下是Circe的一个示例:

import enumeratum.values._

sealed abstract class Status(val value: String) extends StringEnumEntry {
  def name: String = value
}

object Status extends StringEnum[Status] with StringCirceEnum[Status] {
  val values = findValues

  case object NotVerified extends Status("not_verified")
  case object Correct extends Status("correct")
  case object Wrong extends Status("wrong")
}
您可以使用它,而无需明确定义任何编码器/解码器或从Status导入任何内容:


您实现状态的方式有问题,因为您可以创建Statusnot\u verified,但类型将是Status而不是NotVerified,并且类型匹配不会给出正确的结果。你可以将状态抽象化,但我怀疑这会破坏解码器。@Tim Oh。你说得对!谢谢我真的不想要这里的子类型。我想我应该使用一个密封的特征,然后case类扩展它?但是quill/circe想要的解码器/编码器会非常重复……是的,这是进行简单枚举的正确方法。使状态抽象,并使用def applyname:String:Status=。。。它匹配字符串并返回相应的子类。然后Statusnot_verified将返回正确的基础类型。
import enumeratum.values._

sealed abstract class Status(val value: String) extends StringEnumEntry {
  def name: String = value
}

object Status extends StringEnum[Status] with StringCirceEnum[Status] {
  val values = findValues

  case object NotVerified extends Status("not_verified")
  case object Correct extends Status("correct")
  case object Wrong extends Status("wrong")
}
scala> import io.circe.syntax._

scala> val status: Status = Status.Correct
status: Status = Correct

scala> status.asJson
res1: io.circe.Json = "correct"

scala> Decoder[Status].decodeJson(Json.fromString("correct"))
res2: io.circe.Decoder.Result[Status] = Right(Correct)