2013-08-04 75 views
2
中定义的对象内的对象

我的问题是如何使用Scala的reflection package迭代在斯卡拉在定义的对象内的对象?如何迭代斯卡拉

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 
} 

回答

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) 

注意,编译器知道这种情况下对象的列表可以静态类型的列表人口。

+0

这里有一个问题,宏实现必须在'高清值静态访问对象=宏MacroUtils.values_impl' – Pooya

+0

你移动'values'方法的定义是什么?它对我来说完全适用于上面的粘贴。 –

+0

是的,我曾在单位搞错对象 – Pooya

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