编译器耗尽检查以获取从密封特征继承的案例对象列表

时间:2018-08-22 07:53:21

标签: scala

我有以下代码(简体):

sealed trait Status {
    def code: String
}

object Status {
    final case object Failed extends Status {
        val code: String = "failed"
    }

    final case object Succeeded extends Status {
        val code: String = "succeeded"
    }

    val allStatuses = List(Failed, Succeded)
}

是否有一种聪明的方法来确保allStatuses列表中包含Status的所有可能类型,或者是一种可迭代的,详尽的集合的替代方法?

原因是我希望能够通过在每个对象的String上进行匹配将Option[Status]转换为code,或者如果不匹配则返回None他们。而且我希望代码安全,以防将来添加更多可能的状态。

2 个答案:

答案 0 :(得分:0)

您可以通过scala反射获得它们。首先,您需要导入scala-reflect库:

libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value

然后,您必须借助knownDirectSubclasses遍历扩展密封类的所有模块:

import reflect.runtime.universe
import reflect.runtime.currentMirror
import reflect.runtime.universe._

def knownSubmodules[T : TypeTag]: List[T] = {
  def run(symbol: universe.Symbol): List[T] = {
    if (symbol.isModuleClass) {
      val moduleMirror = currentMirror.reflectModule(symbol.asClass.module.asModule)
      List(moduleMirror.instance.asInstanceOf[T])
    }
    else if (symbol.isClass && symbol.asClass.isSealed) {
      symbol.asClass.knownDirectSubclasses.toList.flatMap(run)
    }
    else Nil
  }

  run(symbolOf[T])
}

因此,对于以下继承结构:

sealed trait Base1

case object Foo1 extends Base1

case object Bar1 extends Base1

sealed trait Base2 extends Base1

case object Foo2 extends Base2

case object Bar2 extends Base2

它将返回所有4个对象:

scala> knownSubmodules[Base1]

res1: List[Base1] = List(Bar1, Bar2, Foo2, Foo1)

答案 1 :(得分:0)

我建议这样的事情:

object Status extends Enumeration {

  case class FieldVal(code: String) extends Val(nextId)

  type Status = FieldVal

  val FAILED = FieldVal("Failed")
  val SUCCEEDED = FieldVal("Succeeded")

  def fromString(value: String): Status = {
    values.find(v => v.asInstanceOf[Status].code.equals(value))
      .map(_.asInstanceOf[Status])
      .getOrElse(FAILED)
  }
}