Kva*_*ass 12 scala external-dependencies scala-compiler
我想设计一个Scala程序,它接受Scala文件作为参数,可以自定义程序的执行.特别是,我想在运行时提供包含将由程序调用的方法的实现的文件.如何正确依赖外部文件并在运行时动态调用其方法?理想情况下,我还希望这些文件能够依赖于我的程序中的方法和类.
示例场景:我有一个包含该行的函数val p: Plant = Greenhouse.getPlant(),并且Greenhouse该getPlant方法的类在将在运行时提供的其中一个文件中定义.在该文件中,该方法getPlant返回a Rose,where Rose <: Plant和Plant在原始程序中定义.假设文件仅在运行时加入而不是在编译时加入,我如何实现(或近似)这种相互依赖性?
Ben*_*itz 24
以下是仅使用标准Scala的方法.不明显的东西都在GreenhouseFactory:
package customizable
abstract class Plant
case class Rose() extends Plant
abstract class Greenhouse {
def getPlant(): Plant
}
case class GreenhouseFactory(implFilename: String) {
import reflect.runtime.currentMirror
import tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
import toolbox.u._
import io.Source
val fileContents = Source.fromFile(implFilename).getLines.mkString("\n")
val tree = toolbox.parse("import customizable._; " + fileContents)
val compiledCode = toolbox.compile(tree)
def make(): Greenhouse = compiledCode().asInstanceOf[Greenhouse]
}
object Main {
def main(args: Array[String]) {
val greenhouseFactory = GreenhouseFactory("external.scala")
val greenhouse = greenhouseFactory.make()
val p = greenhouse.getPlant()
println(p)
}
}
Run Code Online (Sandbox Code Playgroud)
将覆盖表达式放在external.scala:
new Greenhouse {
override def getPlant() = new Rose()
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Rose()
Run Code Online (Sandbox Code Playgroud)
唯一棘手的是GreenhouseFactory需要预先添加该import语句以提供对外部文件所需的所有类型和符号的访问.为了简单起见,请制作一个包含所有这些内容的包.
编译器ToolBox有点记录在这里.除了奇怪的导入之外,您真正需要知道的唯一事情是toolbox.parse将字符串(Scala源代码)转换为抽象语法树,toolbox.compile并将抽象语法树转换为带签名的函数() => Any.由于这是动态编译的代码,因此您必须使用转换为Any您期望的类型.
Scala本身不提供这种功能.我知道要做的最简单的方法是使用Twitter"util-eval"库.该库包含对Scala编译器和各种类加载仪式的必要调用,为您节省了大量精力.执行你所描述的内容的调用序列看起来像
val eval = new Eval()
val greenhouse = eval.apply[Greenhouse](new File("path/to/MyGreenhouse.scala"))
val plant = greenhouse.getPlant()
Run Code Online (Sandbox Code Playgroud)
你动态加载的Scala文件需要包含一个表达式,而不是一个类本身,但这很容易做到,基本上就是这样.
new Greenhouse{
def getPlant() = //thing to return the plant
}
Run Code Online (Sandbox Code Playgroud)
据我了解,Twitter使用(或至少使用)此功能将其配置文件作为Scala而不是properties/json/xml.