从字符串生成一个类并在Scala 2.10中实例化它

时间:2012-08-25 14:45:20

标签: scala reflection toolbox scala-2.10

在Scala 2.10中如何从字符串生成一个类(可能使用Toolbox api)以后用Scala的反射进行实例化?

1 个答案:

答案 0 :(得分:53)

W.r.t编译工具箱只能运行表达式=返回值,但不能运行带有编译结果的结果类或文件/字节数组。

然而,仍然可以实现你想要的,因为在Scala中使用隐式值从类型级别到值级别很容易:

修改即可。在2.10.0-RC1中,ToolBox的一些方法已被重命名。 parseExpr现在只有parserunExpr现在称为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

更新#1。如果您不需要java.lang.Class并且只需要实例化已编译的类,则可以直接在提交给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的自由项(该值不必是原语 - 它可以是您的自定义对象)并将标识符绑定到它。然后,该值将按原样用于由工具箱编译和运行的代码中。

该示例使用手动AST程序集,但是可以编写一个解析字符串的函数,查找未绑定的标识符,在某些映射中查找它们的值,然后创建相应的自由项。但是Scala 2.10.0中没有这样的功能。