如何在Scala中的已定义对象中迭代内部对象

时间:2013-08-04 10:02:41

标签: scala

我的问题是如何使用Scala reflection package在Scala中定义对象中的内部对象?

object Units {

    val values = CITIZEN :: WORKER :: Nil // I need something reflectional to list all of the case objects

    case object CITIZEN extends Population
    case object WORKER extends Population
}

2 个答案:

答案 0 :(得分:5)

有很多方法可以做到这一点,但为了性能和(更重要的)类型安全性,我建议在运行时反射中使用宏(编译时反射)。

这是一个使用宏的快速实现:

import scala.language.experimental.macros

object MacroUtils {
  import scala.reflect.macros.Context

  def values = macro MacroUtils.values_impl
  def values_impl(c: Context) = {
    import c.universe._

    val objs = c.enclosingClass.collect {
      case ModuleDef(mods, name, _) if mods hasFlag Flag.CASE => Ident(name)
    }

    c.Expr[List[Any]](
      Apply(Select(reify(List).tree, newTermName("apply")), objs.toList)
    )
  }
}

trait Population

object Units {
  val values = MacroUtils.values
  case object CITIZEN extends Population
  case object WORKER extends Population
}

然后,例如:

scala> val populations: List[Population] = Units.values
populations: List[Population] = List(CITIZEN, WORKER)

请注意,编译器知道可以将case对象列表静态地键入为人口列表。

答案 1 :(得分:1)

我不确定这是否是最好的方法,但现在是:

object Units {

    val values = CITIZEN :: WORKER :: Nil

    trait Population

    case object CITIZEN extends Population

    case object WORKER extends Population

    val reflectionValues = {
        import scala.reflect.runtime.{universe => ru}
        val mirror = ru.runtimeMirror(getClass.getClassLoader)
        val objects = ru.typeOf[Units.type].declarations.filter(_.isModule)
        objects.map(o => mirror.reflectModule(o.asModule).instance.asInstanceOf[Population]).toList
    }

    def main(args: Array[String]) {
        assert(values == reflectionValues)
    }
}