Scala反射:强制初始化对象成员

时间:2014-01-26 16:02:26

标签: scala reflection

Scala小提琴here

import scala.reflect.ClassTag
import scala.language.existentials

class SomeClass[T <: SomeClass[T, R], R] extends EarlyInit[T, R] {}

trait EarlyInit[T <: SomeClass[T, R], R] {
    self: SomeClass[T, R] =>

      val clazz = getClass.getSuperclass
      val potentialFields = clazz.getDeclaredClasses.toList

      potentialFields.foreach {
        field => {
          // This correctly prints out fields of object members.
          // but invokation throws an error every time.
          println(s"${field.getName}")
        }
      }
}

class SomeThing extends SomeClass[SomeThing, Any] {
    val stringTest = "test"
    object name
    object test
}

object SomeThing extends SomeThing {}

val x = SomeThing

如何使用反射访问和初始化对象成员(nametest)?

1 个答案:

答案 0 :(得分:1)

您可以使用scala reflection API实现此目的:

import scala.reflect.runtime.universe._

class SomeClass[T <: SomeClass[T, R]: TypeTag, R] extends EarlyInit[T] {}

class EarlyInit[T: TypeTag] {
  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val reflection  = mirror.reflect(this)

  typeTag[T].tpe.members.filter(_.isModule).foreach(m => reflection.reflectModule(m.asModule).instance)
}

class SomeThing extends SomeClass[SomeThing, Any] {
  val stringTest = "test"

  object name {
    println("name initialized")
  }
  object test {
    println("test initialized")
  }
}

object SomeThing extends SomeThing {}

val x = SomeThing

您需要将EarlyInit作为一个类才能获得TypeTag证据。然后你只需搜索所有模块并访问它们(它们将在过程中初始化)


更新

您还可以简化EarlyInit并删除类型参数。您实际上可以直接从镜像获取Type this

trait EarlyInit {
  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val reflection  = mirror.reflect(this)

  mirror
    .classSymbol(this.getClass)
    .toType
    .members
    .filter(_.isModule)
    .foreach(m => reflection.reflectModule(m.asModule).instance)
}