首页 > 解决方案 > 如何将共享的 Scala 枚举逻辑提取到特征或超类中?

问题描述

我需要定义一堆类似的枚举:

object Color extends MyEnum[Color.Color] {
  type Color = Value
  val Red, Green, Periwinkle = Value
}

object Shape extends MyEnum[Shape.Shape] {
  type Shape = Value
  val Square, Circle, Balbis = Value
}

我想将共享功能提取到抽象类或特征中,以支持 1)applyunapply方法,以及 2)从枚举到其字符串表示的隐式转换:

abstract class MyEnum[T] extends Enumeration {
  implicit def valueToString(value: T): String = value.toString
  implicit def stringToValue(string: String): T = apply(string)

  def unapply(arg: String): Option[T] =
    values.find(_.toString == arg).map(_.asInstanceOf[T])

  def apply(arg: String): T =
    values.find(_.toString == arg)
      .getOrElse(sys.error(s"Invalid value '$arg'"))
      .asInstanceOf[T]
}

这不编译;当我在中添加类型参数时,由于某种原因MyEnum[Color.Color]它会破坏类型。Value

有什么方法可以通过这种枚举语法获得我想要的东西,还是我需要切换到案例对象解决方案(或更复杂的东西)?

标签: scalaenums

解决方案


本博客讨论 Scala 中的枚举地狱scala-enumerations-hell

解决方案不是使用 Scala 的 Enumeration 类型,而是创建自己的 Enumeration 类。这是该博客的抽象类:

abstract class Enum[Enum : ClassTag] { self =>
  val values = {
    import runtime.universe._
    val mirror = runtimeMirror(self.getClass.getClassLoader)
    val classSymbol = mirror.classSymbol(self.getClass)

    classSymbol.toType.members
      .filter(_.isModule)
      .map(symbol => mirror.reflectModule(symbol.asModule).instance)
      .collect { case v: Enum => v }
  }

  def forName(name: String): Option[Enum] = values.find(_.name == name)

  implicit class RichardEnum(enum: Enum) {
    def name: String = enum.toString
  }
}

还有一个框架可以为您提供:lloydmeta/enumeratum


推荐阅读