Generowanie klasy z string i tworzenie jej instancji w Scali 2.10

W Scali 2.10 jak wygenerować klasę z string (prawdopodobnie, używając Toolbox api) później do utworzenia instancji z odbiciem Scali?

Author: om-nom-nom, 2012-08-25

1 answers

Skrzynki narzędzi kompilacji W. r.T mogą uruchamiać tylko wyrażenia = zwracające wartości, ale nie wynikowe klasy lub pliki/tablice bajtów z wynikami kompilacji.

Jednak nadal jest możliwe osiągnięcie tego, co chcesz, ponieważ w Scali tak łatwo jest przejść z poziomu typu do poziomu wartości przy użyciu domyślnych wartości:

Edit . W 2.10.0-RC1 niektóre metody ToolBox zostały przemianowane. parseExpr jest teraz tylko parse, a runExpr nazywa się teraz 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

Update # 1. Jeśli nie potrzebujesz java.lang.Klasy i po prostu trzeba utworzyć instancję skompilowanej klasy, można napisać new C bezpośrednio w ciągu przesłanym do runExpr.

Update # 2. Możliwe jest również, aby runExpr używało niestandardowego mapowania z nazw zmiennych do wartości runtime. Na przykład:

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

W tym przykładzie tworzę wolny termin, który ma wartość 2 (wartość nie musi być prymitywna - może to być twój obiekt niestandardowy) i powiązuję z nim identyfikator. Wartość ta jest następnie używana jako-is w kodzie, który jest skompilowany i uruchomiony przez skrzynkę narzędziową.

Przykład wykorzystuje ręczny montaż AST, ale możliwe jest napisanie funkcji, która parsuje ciąg znaków, wyszukuje niezwiązane identyfikatory, wyszukuje dla nich wartości w niektórych mapach, a następnie tworzy odpowiednie wolne terminy. Nie ma jednak takiej funkcji w Scali 2.10.0.

 52
Author: Eugene Burmako,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-15 12:01:51