通过Scala反射查找封闭实例(如果有)

时间:2013-03-24 03:09:50

标签: scala

我正在尝试使用Scala反射来定义特征案例类,并且他们的同伴可以实现变为“可导出”(例如,Map [String,Any])和“importable”。它适用于顶级案例类,但我无法使其适用于内部类。如果我已经在封闭实例上有一个句柄,我会知道如何反射地实例化一个内部类,我可以将其反映到InstanceMirror,但是现在我正在编写一个稍后将通过顶级或内部类实现的特征

只要协同服务器和构造的实例将共享相同的封闭实例,我就能够完成这项工作。但是我无法弄清楚如何反射地确定同伴的封闭实例。

这是我尝试做的简化示例,以及发生的问题:

import scala.reflect.runtime.universe._;

trait CompanionOfReflectiveConstructable[T] {
  def tType : Type;

  lazy val mirror       : Mirror       = runtimeMirror( this.getClass.getClassLoader );
  lazy val ctorDecl     : Symbol       = tType.declaration(nme.CONSTRUCTOR);
  lazy val ctor         : MethodSymbol = ctorDecl.asMethod;
  lazy val tClass       : ClassSymbol  = tType.typeSymbol.asClass;
  lazy val tClassMirror : ClassMirror  = mirror.reflectClass( tClass );
  lazy val ctorF        : MethodMirror = tClassMirror.reflectConstructor( ctor );

  // in real-life, i'd derive arguments from ctor.paramss
  // but to highlight our issue, we'll assume a no arg constructor
  def createInstance : T = ctorF().asInstanceOf[T]; 
}

trait ReflectiveConstructable;

object Test1 extends CompanionOfReflectiveConstructable[Test1] {
  def tType = typeOf[Test1];
}
class Test1 extends ReflectiveConstructable;

class Outer {
  object Test2 extends CompanionOfReflectiveConstructable[Test2] {
    def tType = typeOf[Test2];
  }
  class Test2 extends ReflectiveConstructable;
}

这是发生了什么。

scala> Test1.createInstance
res0: Test1 = Test1@2b52833d

scala> (new Outer).Test2.createInstance
scala.ScalaReflectionException: class Test2 is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror
        at scala.reflect.runtime.JavaMirrors$JavaMirror.ErrorInnerClass(JavaMirrors.scala:126)
...

Test1效果很好。 Test2的问题很明显 - 我需要通过InstanceMirror而不是通过我的顶级镜像来获取我的ClassMirror。 (请参阅hereherehere。)但是,从CompanionOfReflectiveConstructable中,我不知道如何检查我是内在的还是我的封闭实例,有条件地执行适当的工作。有谁知道怎么做?

非常感谢!

1 个答案:

答案 0 :(得分:1)

我在这里看到的主要问题是你在内部类的伴随对象中使用反射。 Test2类将有一个名为$ outer的字段,它包含外部类,但是,从Test2伴随对象中,您无法获得需要创建Test2的Outer实例。我能看到的唯一工作就是将一个可选实例传递给你的伴侣特征:

trait CompanionOfReflectiveConstructable[T] {
  def tType: Type

  def outer: Option[AnyRef] = None

  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val tClassMirror = outer
    .map(a => mirror.reflect(a).reflectClass(tType.typeSymbol.asClass))
    .getOrElse(mirror.reflectClass(tType.typeSymbol.asClass))

  val ctorF = tClassMirror.reflectConstructor(tType.declaration(nme.CONSTRUCTOR).asMethod)

  // in real-life, i'd derive arguments from ctor.paramss
  // but to highlight our issue, we'll assume a no arg constructor
  def createInstance: T = ctorF().asInstanceOf[T]
}

trait ReflectiveConstructable

class Test1 extends ReflectiveConstructable

object Test1 extends CompanionOfReflectiveConstructable[Test1] {
  def tType = typeOf[Test1]
}

class Outer {

  object Test2 extends CompanionOfReflectiveConstructable[Test2] {
    def tType = typeOf[Test2]
    override def outer = Option(Outer.this)
  }

  class Test2 extends ReflectiveConstructable
}

如果有一种方法可以从Test2伴侣对象中获取Outer实例,那将是很好的,但遗憾的是它在运行时不可用。