45

Scala 2.10では、後で文字列からクラスを生成して(おそらく、Toolbox APIを使用して)、Scalaのリフレクションでインスタンス化するにはどうすればよいですか?

4

1 に答える 1

54

Wrt コンパイル ツールボックスは、式 = 戻り値のみを実行できますが、結果のクラスまたはコンパイル結果を含むファイル/バイト配列は実行できません。

ただし、Scala では暗黙の値を使用して型レベルから値レベルに簡単に移行できるため、目的を達成することはまだ可能です。

編集します。2.10.0-RC1 では、いくつかのメソッドのToolBox名前が変更されました。parseExprは だけparseになり、 とrunExpr呼ばれるようになりevalました。

scala> import scala.reflect.runtime._ // requires scala-reflect.jar
                                      // in REPL it's implicitly added 
                                      // to the classpath
                                      // but in your programs
                                      // you need to do this on your own
import scala.reflect.runtime

scala> val cm = universe.runtimeMirror(getClass.getClassLoader)
cm @ 41d0fe80: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader...

scala> import scala.tools.reflect.ToolBox // requires scala-compiler.jar
                                          // in REPL it's implicitly added 
                                          // to the classpath
                                          // but in your programs
                                          // you need to do this on your own
import scala.tools.reflect.ToolBox

scala> val tb = cm.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@3a962da5

scala> tb.runExpr(tb.parseExpr("class C; scala.reflect.classTag[C].runtimeClass"))
res2: Any = class __wrapper$1$f9d572ca0d884bca9333e251c64e980d$C$1

更新 #1。java.lang.Class を必要とせず、コンパイルされたクラスをインスタンス化するだけでよい場合は、 にnew C送信された文字列に直接書き込むことができますrunExpr

更新 #2。runExpr変数名からランタイム値へのカスタム マッピングを使用することも可能です。例えば:

scala> val build = scala.reflect.runtime.universe.build
build: reflect.runtime.universe.BuildApi = scala.reflect.internal.BuildUtils$BuildImpl@50d5afff

scala> val x = build.setTypeSignature(build.newFreeTerm("x", 2), typeOf[Int])
x: reflect.runtime.universe.FreeTermSymbol = free term x

scala> tb.runExpr(Apply(Select(Ident(x), newTermName("$plus")), List(Literal(Constant(2)))))
res0: Any = 4

この例では、値が 2 のフリー タームを作成し (値はプリミティブである必要はありません。カスタム オブジェクトにすることができます)、識別子をバインドします。この値は、ツールボックスによってコンパイルおよび実行されるコードでそのまま使用されます。

この例では手動の AST アセンブリを使用していますが、文字列を解析し、バインドされていない識別子を見つけ、マッピングでそれらの値を検索し、対応する自由項を作成する関数を作成することは可能です。ただし、Scala 2.10.0 にはそのような関数はありません。

于 2012-08-25T16:16:14.853 に答える