2017-10-17 75 views
1

我想创建一个泛型方法来创建指定的类型参数的类实例。Scala:通过类型参数创建实例

代码变化条件: *尽可能最小变化P1 - P3班 其遗留代码的下方代码只是一个原型,理想没有在所有这些类别的变化。

看到我的代码如下。

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") 

这是错误我得到:

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() 
     ^
+1

你必须帮助编译器。那么类似这样的东西:'def executor [T <:P](cfg:String)(fn:String => T):Unit = fn(cfg).run()'。然后像'executor(“someCfg”)(新的P1(_))'一样使用它。 –

回答

4

你可以这样做:

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() 
} 

并使用它:

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

阅读http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html,只是寻找ClassTagTypeTag会给你更多的信息。

但是,这比其他答案中给出的解决方案更安全:如果该类没有构造函数,则在运行时会失败String

3

信息有关T是失去了在运行时由于类型擦除,所以你不能实例化它

为了满足与P1最小的改动你的要求 - P3类,你将不得不某种工厂函数的传递给executor

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

在这种情况下主叫方会改成这样:

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

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

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

没有改变P1 - P3类。

输出:

1 
2 
3 
+0

我希望有一种魔术,所以它可以通过...谢谢 – Pavel

+1

它是jvm的限制,所以我怀疑它可以避免 – tkachuko

+0

它可以,实际上。看到我的答案。 –