2012-08-25 12 views

Antwort

52

W.r.t Kompilierung Toolboxen können nur Ausdrücke ausführen = Rückgabewerte, aber keine resultierenden Klassen oder Dateien/Byte-Arrays mit Kompilierungsergebnissen.

Allerdings ist es immer noch möglich, zu erreichen, was Sie wollen, da in Scala ist es so einfach vom Typ Ebene Wert Ebene gehen implizite Werten:

bearbeiten. In 2.10.0-RC1 wurden einige Methoden von ToolBox umbenannt. parseExpr ist jetzt nur parse, und runExpr heißt jetzt 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 

Aktualisierung # 1. Wenn Sie keine java.lang.Class benötigen und nur die kompilierte Klasse instanziieren müssen, können Sie new C direkt in die Zeichenfolge schreiben, die an runExpr gesendet wurde.

Aktualisierung # 2. Es ist auch möglich, runExpr benutzerdefinierte Zuordnung von Variablennamen zu Laufzeitwerten zu verwenden. Zum Beispiel:

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 

In diesem Beispiel erstelle ich einen freien Begriff, der einen Wert von 2 (der Wert ein primitiven nicht sein muß - es kann Ihr benutzerdefiniertes Objekt sein) und binden eine Kennung zu. Dieser Wert wird dann unverändert in dem Code verwendet, der von einer Toolbox kompiliert und ausgeführt wird. Das Beispiel verwendet eine manuelle AST-Assemblierung, aber es ist auch möglich, eine Funktion zu schreiben, die einen String analysiert, ungebundene Identifikatoren auffindet, in einem Mapping nach Werten sucht und dann entsprechende freie Terme erstellt. In Scala 2.10.0 gibt es keine solche Funktion.

+0

Danke! Ein Follow-up: Gibt es eine Möglichkeit für mich, diese zurückgegebene 'java.lang.Class' mit Scalas Reflektion in den Griff zu bekommen oder muss ich mich einfach an die alte Java's halten? –

+2

Sicher. Verwenden Sie ' .classSymbol ()', wobei = 'scala.reflect.runtime.universe.runtimeMirror ( .getClassLoader)'. Dann erhalten Sie ein Scala-Reflexionssymbol, das mit der Scala Reflection API überprüft werden kann. –

+0

Warum haben Sie 'universe.runtimeMirror (getClass.getClassLoader)' anstelle von 'reflect.runtime.currentMirror' und' scala.reflect.classTag [C] .runtimeClass' anstelle von 'classOf [C]'? Es stellte sich heraus, dass es auf meinem Ende gut funktionierte. Vielen Dank für die Hilfe, übrigens! –