In Scala 2.10 come si genera una classe da una stringa (probabilmente, usando la Toolbox api) in seguito per essere istanziata con il riflesso di Scala?Generazione di una classe da stringa e istanziazione in Scala 2.10
risposta
Gli strumenti di compilazione W.r.t possono eseguire solo espressioni = valori di ritorno, ma non classi risultanti o array di file/byte con risultati di compilazione.
Tuttavia è ancora possibile ottenere ciò che si vuole, dal momento che in Scala è così facile passare da livello di tipo a livello di valore utilizzando valori impliciti:
Modifica. In 2.10.0-RC1 sono stati rinominati alcuni metodi di ToolBox
. parseExpr
è ora solo parse
e runExpr
è ora chiamato 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
Aggiornamento n. 1. Se non hai bisogno di java.lang.Class e hai solo bisogno di istanziare la classe compilata, puoi scrivere new C
direttamente nella stringa inviata a runExpr
.
Aggiornamento n. 2. È anche possibile che runExpr
utilizzi il mapping personalizzato dai nomi delle variabili ai valori di runtime. Per esempio:
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 questo esempio creo un termine libero che ha un valore di 2 (il valore non deve essere un primitivo - può essere il vostro oggetto personalizzato) e legare un identificatore ad esso. Questo valore viene quindi utilizzato così com'è nel codice che è compilato ed eseguito da una toolbox.
L'esempio utilizza l'assembly AST manuale, ma è possibile scrivere una funzione che analizza una stringa, individua identificatori non associati, cerca valori in alcuni mapping e quindi crea termini corrispondenti corrispondenti. Non c'è però una tale funzione in Scala 2.10.0.
Grazie! Un follow-up: c'è un modo per me di ottenere un handle su questo 'java.lang.Class' restituito con il riflesso di Scala o dovrò semplicemente attenermi a quello di Java precedente? –
Sicuro. Utilizzare ' .classSymbol ()', dove = 'scala.reflect.runtime.universe.runtimeMirror ( .getClassLoader)'. Quindi si ottiene un simbolo di riflessione Scala, che può essere ispezionato con Scala reflection API. –
Perché hai usato 'universe.runtimeMirror (getClass.getClassLoader)' invece di 'reflect.runtime.currentMirror' e' scala.reflect.classTag [C] .runtimeClass' invece di 'classOf [C]'? Si è rivelato che funzionava bene per la mia parte. Grazie mille per l'aiuto, btw! –