3

私は Scala リフレクションを使用してトレイト ケース クラスを定義しようとしています。そのコンパニオンは、"エクスポート可能" (たとえば、Map[String,Any]) および "インポート可能" になるように実装できます。トップレベルのケースクラスではうまく機能していますが、内部クラスでは機能しません。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 を取得する必要があります。(こちらこちら、およびこちらを参照してください。) しかし、CompanionOfReflectiveConstructable 内から、適切な作業を条件付きで実行するために、自分が内側にいるかどうか、または囲んでいるインスタンスが誰であるかを確認する方法がわかりません。誰もこれを行う方法を知っていますか?

どうもありがとう!

4

1 に答える 1

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 インスタンスを取得する方法があればいいのですが、残念ながら実行時には利用できません。

于 2013-04-03T16:35:03.530 に答える