Для моего проекта я внедрил Enum на основе
trait Enum[A] {
trait Value { self: A =>
_values :+= this
}
private var _values = List.empty[A]
def values = _values
}
sealed trait Currency extends Currency.Value
object Currency extends Enum[Currency] {
case object EUR extends Currency
case object GBP extends Currency
}
from Объекты объекта vs Перечисления в Scala. Я работал неплохо, пока не столкнулся с проблемой. Объекты объекта кажутся ленивыми, и если я использую Currency.value, я могу получить пустой список. Было бы возможно сделать вызов против всех значений Enum при запуске, чтобы список значений был заполнен, но это было бы как бы победить точку.
Поэтому я отважился в темные и неизвестные места отражения scala и придумал это решение, основываясь на следующих ответах SO. Могу ли я получить список времени для всех объектов case, которые получены из запечатанного родителя в Scala? и Как я могу получить фактический объект, на который ссылается отражение scala 2.10?
import scala.reflect.runtime.universe._
abstract class Enum[A: TypeTag] {
trait Value
private def sealedDescendants: Option[Set[Symbol]] = {
val symbol = typeOf[A].typeSymbol
val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
if (internal.isSealed)
Some(internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol)
else None
}
def values = (sealedDescendants getOrElse Set.empty).map(
symbol => symbol.owner.typeSignature.member(symbol.name.toTermName)).map(
module => reflect.runtime.currentMirror.reflectModule(module.asModule).instance).map(
obj => obj.asInstanceOf[A]
)
}
Удивительная часть этого заключается в том, что она действительно работает, но она уродливая, и я был бы заинтересован, если бы было возможно сделать это более простым и элегантным и избавиться от вызовов asInstanceOf.