在动态实例化中完美地处理scala构造函数

时间:2015-12-11 16:18:44

标签: scala

我将这个工作代码放在一起,动态地实例化给定name: String(下面)的类。这适用于容易的case - 具有一个构造函数的类和case类。

我不知道如何处理存在多个构造函数的一般情况。我认为它们只能通过它们的签名来区分,但是发现伴随对象,类和案例类之间的概念交互有点令人困惑。什么是所有"建筑"的完整描述?需要考虑的场景,或者,您将如何将其演变为完全通用?

证明它的不灵活性,这段代码难以通过伴侣对象。

希望这段代码能够提供方便的测试和测试。如果有人关心加入这个思想训练,那就是修补流。

import scala.reflect.runtime.universe

case class CaseClass(foo: Int) {
  println(s"${getClass.getSimpleName} Instantiated with $foo")
}

class BaseClass(foo: Int) {
  println(s"${getClass.getSimpleName} Instantiated with $foo")
}

object BaseClass { 
  def apply(foo:Int) = {
    println(s"going through companion object ${getClass.getSimpleName}")
    new BaseClass(foo+10) }
  }

class GenericClass[T](foo: T) {
  println(s"${getClass.getSimpleName} Instantiated with $foo")
}

object Inst {

  private def log(s: String) = println(Console.YELLOW + Console.BOLD + s + Console.RESET)

  private def selectConstructor(symbol: universe.Symbol) = {
    val constructors = symbol.typeSignature.members.filter(_.isConstructor).toList
    if (constructors.length > 1) log(
           s"""Warning: $symbol has several constructors, arbitrarily picking the first one: 
              |         ${constructors.mkString("\n         ")}""".stripMargin)
    constructors.head.asMethod
  }

  def apply(className: String, arg: Any) = {
    val runtimeMirror: universe.Mirror = universe.runtimeMirror(getClass.getClassLoader)

    val classSymbol: universe.ClassSymbol = runtimeMirror.classSymbol(Class.forName(className))

    val classMirror: universe.ClassMirror = runtimeMirror.reflectClass(classSymbol)

    if (classSymbol.companion.toString() == "<none>") // TODO: use nicer method "hiding" in the api?
    {
      log(s"Info: $className has no companion object")
      val constructorMirror = classMirror.reflectConstructor(selectConstructor(classSymbol)) // we can reuse it
      constructorMirror(arg)
    }
    else
    {
      val companionSymbol = classSymbol.companion
      log(s"Info: $className has companion object $companionSymbol")
      val constructorMirror = classMirror.reflectConstructor(selectConstructor(classSymbol)) // we can reuse it
      constructorMirror(arg)
    }   
  }
}

object Test extends App {
  val c1 = Inst("BaseClass", 3)
  val c2 = Inst("BaseClass", 4)
  val cc = Inst("CaseClass", 5)
  val gc1 = Inst("GenericClass", "I am generic")
  val gc2 = Inst("GenericClass", gc1)
  println(s"""\nthese objects have been instantiated:\n${List(c1,c2,cc,gc1,gc2).mkString("\n")}""")
}

请注意,它需要此build.sbt或类似的:

lazy val reflection = (project in file("."))
  .settings(
    scalaVersion := "2.11.7",
    libraryDependencies ++= Seq(
      "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
      "org.scala-lang" % "scala-library" % scalaVersion.value % "provided"
    )
  )

0 个答案:

没有答案