Scala:如何从Type中获取Class [_]实例?

时间:2015-02-07 12:02:09

标签: scala reflection

我正在实施深度运行时反射。 给定一个universe.Type,我可以获得该类型的运行时类实例吗? ClassTags不会帮助我,因为他们丢失了类型参数信息。 鉴于以下类别:

case class One[T](item :T)
case class Parent(id :Long)
case class Child(id :Long, parent :One[Parent])

当给出Child的typeTag(可能是classTag)时,我不能确定,parent.value运行时类应该是Class [Parent]。当然,我希望它能够递归地处理更复杂的例子。

编辑: 我本可以说得更清楚,我有兴趣不识别被检查类型本身的类型参数,而是确定其方法的具体返回类型。更确切地说,给定Typejava.lang.reflect.Method,我希望能够确定此方法应返回的类。我能够使用手动类型映射为我的例子做到这一点:

            val typeMapping = (parentType.typeConstructor.typeParams zip parentType.typeArgs.map(_.dealias)).toMap
            System.err.println(s"type mapping for $parentType: ${parentType.typeParams} -> ${parentType.typeArgs}")
            val methods =
                for (symbol <- parentType.member(TermName(method.getName)).alternatives; if noArgMethod(symbol))
                    yield symbol.asMethod

            val returnType = methods match {
                case Seq() => throw new IllegalArgumentException(s"coulnd't find a method symbol for $method in type $parentType!. Programming error, sorry")
                case Seq(m) =>
                    val possiblyGeneric = m.asMethod.returnType.dealias
                    typeMapping.getOrElse(possiblyGeneric.typeSymbol, possiblyGeneric)
                case _ => throw new IllegalArgumentException(s"multiple method symbols for $method in $parentType: $methods")
            }

但我希望它在任何更复杂的情况下都会失败,例如,返回的类型T是别名,或者是封闭类的类型参数,而不是声明类或其他内容。由于拥有typeTag可以保证类型被完全实例化,因此应该可以将任何抽象(代替声明)类型解析为完全实例化的类型。我认为这个任务过于复杂/有风险,无法在专用库之外处理,理想情况下应由反射API提供。

1 个答案:

答案 0 :(得分:2)

如果您将类型参数放在要检查的类上,然后创建TypeTag,您可以使用.typeArgs来至少获取类名:

  import scala.reflect.runtime.universe._

  case class One[T](item :T)
  case class Parent(id :Long)
  case class Child[S, T[S]](id: Long, parent: T[S])

  def junk[T: TypeTag](v: T) = {
    val t = implicitly[TypeTag[T]]
    t.tpe.typeArgs.map { a =>
      val m = runtimeMirror(getClass.getClassLoader)
      println(m.runtimeClass(a.typeSymbol.asClass))
    }
  }

  junk(Child(10L, One(Parent(11L))))
  junk(List(10,20,30))

输出是:

class org.example.Ex1$Parent
class org.example.Ex1$One

int

编辑:您可以通过使用镜像来获得更具代表性的构造函数。

  def junk[T: TypeTag](v: T) = {
    val t = implicitly[TypeTag[T]]
    val m = runtimeMirror(getClass.getClassLoader)
    val instanceMirror = m.reflectClass(typeOf[T].typeSymbol.asClass)
    val ctorMethod = typeOf[T].declaration(nme.CONSTRUCTOR).asMethod
    val ctorRef = instanceMirror.reflectConstructor(ctorMethod)
    ctorRef(20L, One(Parent(22L)))
  }

如果这些工具无法完成您尝试做的事情,您可能需要开始查看宏。