简体   繁体   中英

Scala: create instance by type parameter

I am trying to create a generic method to create class instance by specified type parameter.

Code change conditions: * as minimum as possible changes to P1 - P3 classes its a legacy code an code below is just a prototype, ideally no changes at all to these classes.

See my code below.

trait P {
  def run() : Unit = ???
}

class P1 (cfg : String ) extends P {
  override def run() : Unit = {
    println("1")
  }
}

class P2 (cfg : String )extends P {
  override def run() : Unit = {
    println("2")
  }
}

class P3 (cfg : String ) extends P {
  override def run() : Unit = {
    println("3")
  }
}



  def executor[T <: P](cfg: String): Unit  = {
    new T(cfg).run()
  }

executor[P1]("someCfg")

executor[P2]("someCfg")

executor[P3]("someCfg")

Here is error I am getting:

Error:(26, 10) class type required but T found
    new T(cfg).run()
        ^
Error:(53, 10) class type required but T found
    new T(cfg).run()
        ^

You can do this:

import scala.reflect.ClassTag

def executor[T <: P](cfg: String)(implicit tag: ClassTag[T]): Unit  = {
  tag.runtimeClass.getConstructor(classOf[String]).
    newInstance(cfg).asInstanceOf[T].run()
}

And use it:

executor[P1]("someCfg")
executor[P2]("someCfg")
executor[P3]("someCfg")

Reading http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html and simply searching for ClassTag and TypeTag will give you more information.

However, this is less safe than the solution given in the other answer: it'll fail at runtime if the class doesn't have a constructor taking String .

Information about T is lost in runtime due to type erasure , therefore you cannot instantiate it .

In order to satisfy your requirements with minimal changes of P1 - P3 classes you would have to pass some kind of factory function to executor :

  def executor[T <: P](cfg: String)(fct: String => T): Unit = {
    fct(cfg).run()
  }

In this case calling side would change to this:

  executor("someCfg")(new P1(_))

  executor("someCfg")(new P2(_))

  executor("someCfg")(new P3(_))

with no changes to P1 - P3 classes.

Output:

1
2
3

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM