In Scala 2.10 wie erzeuge ich eine Klasse aus string (wahrscheinlich mit der Toolbox api), um später mit Scalas Reflektion instanziiert zu werden?Generieren einer Klasse aus String und Instanziieren in Scala 2.10
Antwort
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.
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? –
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. –
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! –