標準の 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)
}
}
オーバーライド式を に入れますexternal.scala
:
new Greenhouse {
override def getPlant() = new Rose()
}
出力は次のとおりです。
Rose()
唯一のトリッキーな点は、外部ファイルが必要とするすべての型とシンボルへのアクセスを提供するために、GreenhouseFactory
そのステートメントを先頭に追加する必要があることです。import
それを簡単にするために、これらすべてを含む単一のパッケージを作成します。
コンパイラは、ここToolBox
に文書化されています。奇妙な imports以外に、本当に知っておく必要がある唯一のことは、文字列 (Scala ソース コード) を抽象構文木に変換し、抽象構文木を signature を持つ関数に変換することです。これは動的にコンパイルされるコードであるため、期待する型にキャストする必要があります。toolbox.parse
toolbox.compile
() => Any
Any