代码之家  ›  专栏  ›  技术社区  ›  beta Rob

组织与类型关联的scala隐式

  •  0
  • beta Rob  · 技术社区  · 6 年前

    我想介绍一些类型来表示较大类型中字段的可能值。这些字段需要能够编码/解码到/来自JSON,也能够写入/读取到数据库。

    我对scala还是个新手,我想要的类型是sum类型 Status = NotVerified | Correct | Wrong . 由于我希望有一个与每个构造函数关联的字符串表示,所以我创建了一个密封的case类,其中 String 参数,然后是扩展该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(_))
      }
    }
    

    然后明确 import 这些是需要的,但这很明确。

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

    2 回复  |  直到 6 年前
        1
  •  1
  •   Kolmar    6 年前

    通常的方法是定义 sealed trait :

    sealed trait Status {
      def name: String
    }
    
    object Status {
      case object NotVerified extends Status {
        val name = "not_verified"
      }
      case object Correct extends Status {
        val name = "correct"
      }
      case object Wrong extends Status {
        val name = "wrong"
      }
    }
    

    或A sealed abstract class ,在当前的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")
    }
    

    为了避免需要导入implicit,可以将它们直接放置在类型的伴生对象中。另见问题 Where does Scala look for implicits? 更多细节,尤其是章节 类型的伴生对象 .

    是的,为这样的枚举定义隐式很容易重复。你必须借助反射或宏。我建议使用 Enumeratum 图书馆,它还集成了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 以下内容:

    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)
    
        2
  •  0
  •   Tim    6 年前

    如果添加 apply 方法可以创建适当的 Status 从A String ,这应该使 Decoder 工作正常。制作 状态 摘要

    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
      }
    }
    

    我认为你现有的暗示仍然有效,但我不知道那些特定的图书馆…

    推荐文章