2012-08-25 21 views

Respuesta

52

Las cajas de herramientas de compilación de W.r.t solo pueden ejecutar expresiones = valores de retorno, pero no clases resultantes o conjuntos de archivos/bytes con resultados de compilación.

Sin embargo, todavía es posible lograr lo que desea, ya que en Scala es tan fácil pasar de nivel de tipo a nivel de valor utilizando valores implícitos:

Editar. En 2.10.0-RC1 algunos métodos de ToolBox han cambiado de nombre. parseExpr ahora es solo parse, y runExpr ahora se llama 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 

Actualización # 1. Si no necesita un java.lang.Class y solo necesita crear una instancia de la clase compilada, puede escribir new C directamente en la cadena enviada al runExpr.

Actualización n. ° 2. También es posible hacer que runExpr utilice una asignación personalizada desde nombres de variables a valores de tiempo de ejecución. Por ejemplo:

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 

En este ejemplo se crea un término libre que tiene un valor de 2 (el valor no tiene por qué ser una primitiva - puede ser el objeto personalizado) y enlazar un identificador a la misma. Este valor se usa tal cual en el código que se compila y ejecuta con una caja de herramientas.

El ejemplo usa el ensamblaje AST manual, pero es posible escribir una función que analiza una cadena, descubre identificadores independientes, busca valores en alguna asignación y luego crea los términos libres correspondientes. Sin embargo, no existe tal función en Scala 2.10.0.

+0

Gracias! Un seguimiento: ¿hay alguna manera de manejar este retorno 'java.lang.Class' con el reflejo de Scala o tendré que quedarme con el viejo Java simple? –

+2

Sure. Use ' .classSymbol ()', donde = 'scala.reflect.runtime.universe.runtimeMirror ( .getClassLoader)'. Luego obtienes un símbolo de reflexión Scala, que se puede inspeccionar con la API Scala reflection. –

+0

¿Por qué usaste 'universe.runtimeMirror (getClass.getClassLoader)' en lugar de 'reflect.runtime.currentMirror' y' scala.reflect.classTag [C] .runtimeClass' en lugar de 'classOf [C]'? Resultó estar funcionando bien en mi extremo. ¡Muchas gracias por la ayuda, por cierto! –

Cuestiones relacionadas