45 votes

La génération d'une classe à partir de la chaîne et de son instanciation dans Scala 2.10

En Scala 2.10 comment puis-je créer une classe à partir de la chaîne (probablement, à l'aide de la boîte à outils api) plus tard pour être instancié avec Scala, à la réflexion?

53voto

Eugene Burmako Points 8453

W. r.t compilation des boîtes à outils ne peuvent exécuter des expressions = valeur de retour, mais n'entraînant pas de classes ou de fichiers/tableaux d'octets à la compilation des résultats.

Cependant, il est toujours possible d'obtenir ce que vous voulez, puisque dans Scala c'est tellement facile de passer de niveau de type de valeur niveau à l'aide de valeurs implicites:

Edit. Dans 2.10.0-RC1 certaines méthodes d' ToolBox ont été renommés. parseExpr est maintenant juste parse, et runExpr est maintenant appelé 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] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@3a962da5

scala> tb.runExpr(tb.parseExpr("class C; scala.reflect.classTag[C].runtimeClass"))
res2: Any = class __wrapper$1$f9d572ca0d884bca9333e251c64e980d$C$1

Mise à jour #1. Si vous n'avez pas besoin d'un java.lang.Class et juste besoin d'instancier la classe compilée, vous pouvez écrire new C directement dans la chaîne soumise à l' runExpr.

Mise à jour #2. Il est également possible d'avoir des runExpr utiliser un mappage personnalisé à partir des noms de variables à des valeurs de l'exécution. Par exemple:

scala> val build = scala.reflect.runtime.universe.build
build: reflect.runtime.universe.BuildApi = scala.reflect.internal.BuildUtils$BuildImpl@50d5afff

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

Dans cet exemple, j'ai créer gratuitement un terme qui a une valeur de 2 (la valeur n'a pas à être une primitive - il peut être votre objet personnalisé) et de lier un identifiant à elle. Cette valeur est ensuite utilisée dans le code est compilé et exécuté par une boîte à outils.

L'exemple utilise le manuel de l'AST de l'assemblée, mais il est possible d'écrire une fonction qui analyse une chaîne, découvre déliés identifiants, recherche des valeurs dans certains cartographie et ensuite crée les conditions de gratuité. Il n'y a pas une telle fonction dans Scala 2.10.0 bien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X