2012-08-25 4 views

答えて

52

W.r.tコンパイルツールボックスは式の実行のみ可能ですが、結果のクラスまたはコンパイル結果のファイル/バイト配列は返しません。 Scalaで、それは暗黙の値を使用して値レベルにタイプレベルから行くことは簡単だから

しかしそれは、あなたが望むものを達成することは可能です:

編集。 2.10.0-RC1では、ToolBoxのいくつかのメソッドの名前が変更されました。 parseExprは現在parseになり、runExprevalとなりました。

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にはそのような機能はありません。

+0

ありがとうございます! 1つのフォローアップ:返された 'java.lang.Class'をScalaのリフレクションで処理する方法がありますか?それとも普通の古いJavaのものに固執しなければなりませんか? –

+2

' .classSymbol(<インスタンスのjava.lang.Class>) 'を使用してください。ここで =' scala.reflect.runtime.universe.runtimeMirror(<インスタンスの例> java.lang.Class> .getClassLoader) '。次にScalaのリフレクションシンボルを取得します。このシンボルはScalaリフレクションAPIで検査できます。 –

+0

なぜあなたは 'classOf [C]'の代わりに 'reflect.runtime.currentMirror'と' scala.reflect.classTag [C] .runtimeClass'の代わりに 'universe.runtimeMirror(getClass.getClassLoader)'を使いましたか?それは私の最後にうまくいっていることが分かった。助けてくれてありがとう、btw! –