Scala 2.10では、後でScalaのリフレクションでインスタンス化するために、文字列からクラスを生成するにはどうすればいいですか?文字列からクラスを生成してScala 2.10でインスタンス化する
45
A
答えて
52
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] = [email protected]
scala> tb.runExpr(tb.parseExpr("class C; scala.reflect.classTag[C].runtimeClass"))
res2: Any = class __wrapper$1$f9d572ca0d884bca9333e251c64e980d$C$1
更新#1。 java.lang.Classを必要とせず、コンパイルされたクラスをインスタンス化する必要がある場合はrunExpr
に提出された文字列に直接new C
を書くことができます。
更新#2。 runExpr
に変数名から実行時の値へのカスタムマッピングを使用することもできます。たとえば:
scala> val build = scala.reflect.runtime.universe.build
build: reflect.runtime.universe.BuildApi = [email protected]
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にはそのような機能はありません。
関連する問題
ありがとうございます! 1つのフォローアップ:返された 'java.lang.Class'をScalaのリフレクションで処理する方法がありますか?それとも普通の古いJavaのものに固執しなければなりませんか? –
' .classSymbol(<インスタンスのjava.lang.Class>) 'を使用してください。ここで =' scala.reflect.runtime.universe.runtimeMirror(<インスタンスの例> java.lang.Class> .getClassLoader) '。次にScalaのリフレクションシンボルを取得します。このシンボルはScalaリフレクションAPIで検査できます。 –
なぜあなたは 'classOf [C]'の代わりに 'reflect.runtime.currentMirror'と' scala.reflect.classTag [C] .runtimeClass'の代わりに 'universe.runtimeMirror(getClass.getClassLoader)'を使いましたか?それは私の最後にうまくいっていることが分かった。助けてくれてありがとう、btw! –