2012-08-25 10 views

Odpowiedz

52

Przyborniki kompresji W.r.t mogą uruchamiać tylko wyrażenia = wartości zwracane, ale nie otrzymane klasy lub zbiory plików/bajtów z wynikami kompilacji.

Jednak to wciąż możliwe do osiągnięcia, co chcesz, ponieważ w Scala to tak łatwo przejść z poziomu typu do poziomu wartości za pomocą wartości ukryte:

Edit. W 2.10.0-RC1 zmieniono niektóre metody ToolBox. 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] = [email protected] 

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

Aktualizacja # 1. Jeśli nie potrzebujesz klasy java.lang.Class i potrzebujesz tylko utworzyć instancję skompilowanej klasy, możesz napisać new C bezpośrednio w ciągu znaków przesłanym do runExpr.

Aktualizacja # 2. Możliwe jest również użycie niestandardowego mapowania od nazw zmiennych do wartości środowiska wykonawczego. Na przykład:

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 

W tym przykładzie utworzyć wolnego terminu, który ma wartość 2 (wartość nie musi być prymitywny - może to być Twój obiekt niestandardowy) i powiązać identyfikator do niego. Ta wartość jest następnie używana jako-jest w kodzie, który jest skompilowany i uruchamiany przez przybornik.

W przykładzie wykorzystano ręczny montaż AST, ale możliwe jest napisanie funkcji, która analizuje ciąg znaków, wykrywa niezwiązane identyfikatory, wyszukuje wartości dla nich w niektórych mapowaniach, a następnie tworzy odpowiednie wolne terminy. W Scali 2.10.0 nie ma takiej funkcji.

+0

Dzięki! Jedna z obserwacji: czy istnieje sposób, aby uzyskać uchwyt na tym zwróconym 'java.lang.Class' z refleksją Scali, czy po prostu będę musiał trzymać się zwykłego starego Javy? –

+2

Pewnie. Użyj ' .classSymbol ()', gdzie = 'scala.reflect.runtime.universe.runtimeMirror ( .getClassLoader)'. Otrzymasz symbol odbicia Scala, który można sprawdzić za pomocą interfejsu API Scala reflection. –

+0

Dlaczego użyłeś 'universe.runtimeMirror (getClass.getClassLoader)' zamiast 'reflect.runtime.currentMirror' i' scala.reflect.classTag [C] .runtimeClass' zamiast 'classOf [C]'? Okazało się, że działa dobrze na moim końcu. Wielkie dzięki za pomoc, btw! –

Powiązane problemy