如何使用object.getClass动态获取为密封特征实现的类集(而不是使用类型参数)?

时间:2014-09-11 00:12:40

标签: scala reflection traits sealed

要点:
使用包含sealed trait及其所有实现者的对象,如何使用包含对象的sealed trait方法获取所有getClass实现者​​的类名集(相反)使用类型参数)?


详细说明:
我目前正在使用Scala 2.11.2并尝试从sealed trait获取后代集。我见过Travis Brown's solution。但是,它使用类型参数Root: TypeTag。我需要能够通过Symbol实例的object方法在运行时动态发现getClass来为扫描提供种子。

考虑这个示例类:

object SealedTest {
  sealed trait T
  case object A extends T
  case object B extends T
}

我的目标是在object SealedTest之外设置一个看起来像这样的函数:

def getSealedTraitImplementers(clazz: Class[_]): Set[String]

致电getSealedTraitImplementers(SealedTest.T.getClass)将返回Set(A, B)。而且我确实获得了SealedTest.T的课程比简化示例更为复杂(实际完整的详细信息在下面的val sealedDescendantsViaClassInstance中)。


这是我到目前为止所尝试的内容:

使用Travis的代码作为起点,我创建了这个函数:

def inspect(symbol: Symbol): Option[Set[Symbol]] = {
  val internal = symbol.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
  if (internal.isSealed)
    Some(internal.sealedDescendants.map(_.asInstanceOf[Symbol]) - symbol)
  else None
}

然后我采用他原来的主要入口点并将其定义为:

def sealedDescendants[Root: TypeTag]: Option[Set[Symbol]] = {
  val symbol = typeOf[Root].typeSymbol
  inspect(symbol)
}

当这样调用时,这成功返回Set(object A, object B)

val resultSealedDescendants =
  sealedDescendants[SealedTest.T] match {
    case Some(set) => set.toString
    case None => "<empty>"
  }
println(s"sealedDescendants[SealedTest.T]=${resultSealedDescendants}")

虽然它不是Set[String],但使用resultSealedDescendants.map(_.toString.stripPrefix("object ")到达那里是微不足道的。


现在,因为我无法上班。我定义此函数以从Symbol的现有运行时类实例中获取SealedTest.T

def sealedDescendantsViaClassInstance: Option[Set[Symbol]] = {
  val classSealedTestT = Class.forName(SealedTest.getClass.getName + "T")
  val runtimeMirrorTemp = runtimeMirror(classSealedTestT.getClassLoader)
  val classSymbol = runtimeMirrorTemp.staticClass(classSealedTestT.getName)

  //???missing transform of ClassSymbol to Symbol???

  inspect(classSymbol)
}

当这样调用时,返回<empty>时失败了:

val resultSealedDescendantsViaClassInstance =
  sealedDescendantsViaClassInstance match {
    case Some(set) => set.toString
    case None => "<empty>"
  }
println(s"sealedDescendantsViaClassInstance=$resultSealedDescendantsViaClassInstance")

我显然正在获得SymbolClassSymbol更精确)。但是,inspect函数未返回Set。所以,我认为在调用classSymbol之前,我需要在inspect上进行一些转换。失踪的转变是什么?

<小时/>
更新:
在花了好几个小时试图缩小这个差距后,我放弃并修改了原始对象以添加(丑陋的)显式类型类。这不是理想的解决方案。该对象现在看起来像这样:

object SealedTest {
  sealed trait T
  case object A extends T
  case object B extends T
  def typeTagT: TypeTag[_] = typeTag[SealedTest.T]
}

我仍然需要原始要求才能从getClass T开始。所以,如果你有任何线索我可以从那里开始动态构成一个类型类,它可以产生sealed trait T所需的符号,我真的很感激。如果我最终搞清楚,我会发一个答案。

0 个答案:

没有答案