从字符串生成一个类并在 Scala 2.10 中实例化它 [英] Generating a class from string and instantiating it in Scala 2.10
问题描述
在 Scala 2.10 中,我如何从字符串(可能使用 Toolbox api)生成一个类,以便稍后使用 Scala 的反射进行实例化?
W.r.t 编译工具箱只能运行表达式 = 返回值,但不能运行带有编译结果的类或文件/字节数组.
但是仍然可以实现您想要的,因为在 Scala 中使用隐式值可以很容易地从类型级别转到值级别:
编辑.在 2.10.0-RC1 中,ToolBox
的一些方法已被重命名.parseExpr
现在只是 parse
,runExpr
现在被称为 eval
.
scala>import scala.reflect.runtime._//需要 scala-reflect.jar//在 REPL 中它是隐式添加的//到类路径//但在你的程序中//你需要自己做这件事导入 scala.reflect.runtime标度>val cm = Universe.runtimeMirror(getClass.getClassLoader)cm @ 41d0fe80:reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader...标度>import scala.tools.reflect.ToolBox//需要 scala-compiler.jar//在 REPL 中它是隐式添加的//到类路径//但在你的程序中//你需要自己做这件事导入 scala.tools.reflect.ToolBox标度>val tb = cm.mkToolBox()tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@3a962da5标度>tb.runExpr(tb.parseExpr("class C; scala.reflect.classTag[C].runtimeClass"))res2: Any = class __wrapper$1$f9d572ca0d884bca9333e251c64e980d$C$1
更新 #1.如果不需要java.lang.Class,只需要实例化编译好的类,可以直接在提交给runExpr
的字符串中写new C
.>
更新#2.也可以让 runExpr
使用从变量名称到运行时值的自定义映射.例如:
scala>val build = scala.reflect.runtime.universe.build构建:reflect.runtime.universe.BuildApi = scala.reflect.internal.BuildUtils$BuildImpl@50d5afff标度>val x = build.setTypeSignature(build.newFreeTerm("x", 2), typeOf[Int])x:reflect.runtime.universe.FreeTermSymbol = 免费项 x标度>tb.runExpr(Apply(Select(Ident(x), newTermName("$plus")), List(Literal(Constant(2)))))res0:任意 = 4
在本例中,我创建了一个值为 2 的自由项(该值不必是原始值 - 它可以是您的自定义对象)并为其绑定一个标识符.然后在由工具箱编译和运行的代码中按原样使用该值.
该示例使用手动 AST 汇编,但可以编写一个函数来解析字符串,找出未绑定的标识符,在某些映射中查找它们的值,然后创建相应的自由项.Scala 2.10.0 中没有这样的功能.
In Scala 2.10 how do I generate a class from string (probably, using the Toolbox api) later to be instantiated with Scala's reflection?
W.r.t compilation toolboxes can only run expressions = return values, but not resulting classes or files/byte arrays with compilation results.
However it's still possible to achieve what you want, since in Scala it's so easy to go from type level to value level using implicit values:
Edit. In 2.10.0-RC1 some methods of ToolBox
have been renamed. parseExpr
is now just parse
, and runExpr
is now called 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. If you don't need a java.lang.Class and just need to instantiate the compiled class, you can write new C
directly in the string submitted to runExpr
.
Update #2. It is also possible to have runExpr
use custom mapping from variable names to runtime values. For example:
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
In this example I create a free term that has a value of 2 (the value doesn't have to be a primitive - it can be your custom object) and bind an identifier to it. This value is then used as-is in the code that is compiled and run by a toolbox.
The example uses manual AST assembly, but it's possible to write a function that parses a string, finds out unbound identifiers, looks up values for them in some mapping and then creates corresponding free terms. There's no such function in Scala 2.10.0 though.
这篇关于从字符串生成一个类并在 Scala 2.10 中实例化它的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!