Scala 2.10では、後で(おそらくToolbox apiを使用して)文字列からクラスを生成し、Scalaのリフレクションでインスタンス化する方法を教えてください。)
W.r.tコンパイルツールボックスは式=戻り値のみを実行できますが、結果のクラスまたはファイル/コンパイル結果を含むバイト配列は実行できません。
ただし、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 Assemblyを使用していますが、文字列を解析し、バインドされていない識別子を見つけ、マッピングでそれらの値を検索し、対応する無料の用語を作成する関数を作成することは可能です。そのような関数はScala 2.10.0ですが。