Создание класса из строки и создание его экземпляра в Scala 2.10

в Scala 2.10 как создать класс из строки (возможно, с помощью API Toolbox) позже, чтобы создать экземпляр с отражением Scala?

1 ответов


W. r.t наборы инструментов компиляции могут запускать только выражения = возвращаемые значения, но не результирующие классы или файлы/байтовые массивы с результатами компиляции.

однако все еще можно достичь того, что вы хотите, так как в Scala так легко перейти от уровня типа к уровню значения, используя неявные значения:

редактировать. В 2.10.0-RC1 некоторые методы ToolBox были переименованы. parseExpr - это теперь просто parse и runExpr сейчас называется 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$f9d572ca0d884bca9333e251c64e980d$C

обновление #1. Если вам не нужна java.ленг.Класс и просто нужно создать экземпляр скомпилированного класса, вы можете написать new C непосредственно в строке, представленный runExpr.

обновление #2. Также возможно иметь runExpr используйте пользовательское сопоставление имен переменных со значениями времени выполнения. Например:

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

в этом примере я создаю бесплатный термин, который имеет значение 2 (значение не должно быть примитивным - это может быть ваш заказ object) и привязать к нему идентификатор. Это значение затем используется в код, который компилируется и выполняется с помощью инструментов.

в примере используется ручная сборка AST, но можно написать функцию, которая анализирует строку, находит несвязанные идентификаторы, ищет для них значения в некотором сопоставлении, а затем создает соответствующие свободные термины. Однако в Scala 2.10.0 такой функции нет.