Scala Generic, specify generic through variable

时间:2016-08-31 12:31:18

标签: scala generics

I have a class which takes a generic as such:

class MyClass[T <: RecordType] (myRecordType: T) {
  def doAction() : Unit =
  {
    myRecordType.someMethod();
  }
}

I have a series of subclasses of RecordType that all implement someMethod(). Currently, i call each one individually in my main class as follows:

def main(args: Array[String]): Unit = 
{
   new MyClass[RecordType10](new RecordType10()).doAction();
   new MyClass[RecordType20](new RecordType20()).doAction();
   new MyClass[RecordType30](new RecordType30()).doAction();
   // many more record types each repeated
}

Ideally, instead of adding a new line for every record type, we would love to have an enumeration of valid record types and just loop through. This way, adding new record types would be as simple as adding to the pre-defined list. But I cannot figure out how to have an Array or Enumeration of class types and then pass those to the instantiation of MyClass. For example, this simple test:

val testClass = classOf(RecordType10);
new MyClass[testClass](new testClass()).doAction();

... it does not compile.

So basic question is: is there a way to have a collection of classes and then iterate through that collection and instantiate another class passing the value for the generic type. Something like this:

val myClasses = Array(classOf(Record10), classOf(Record20), classOf(Record30));
for (theClass <- myClasses)
{
   new MyClass[theClass](new theClass()).doAction();
}

Looking forward to any response. Thanks!

3 个答案:

答案 0 :(得分:2)

为简单起见,使用OP的例子:

object Main {
  trait RecordType {
    def someMethod()
  }

  class MyClass[T <: RecordType](myRecordType: T) {
    def doAction(): Unit = myRecordType.someMethod()
  }

  class RecordType10() extends RecordType {
    override def someMethod(): Unit = println("some method 10")
  }

  class RecordType20() extends RecordType {
    override def someMethod(): Unit = println("some method 20")
  }

  def main(args: Array[String]): Unit = {
    new MyClass[RecordType10](new RecordType10()).doAction()
    new MyClass[RecordType20](new RecordType20()).doAction()

    val myClasses = List(classOf[RecordType10], classOf[RecordType20])
    for(theClass <- myClasses) {
      val instance = theClass.newInstance()
      val m = new MyClass(instance)
      m.doAction()
    }
  }
}

答案 1 :(得分:1)

编辑:通过亚历山大的解决方案简化以获取类名。

这样可行,但我不知道自动构建该列表的方法(可能通过反射某种方式)。

trait A {def say = println("Hello")}
class B extends A {override def say = println("Hello B")}
class C extends A {override def say = println("Hello C")}

val ls:  List[Class[_ <: A]]= List(classOf[B],classOf[C])

ls.foreach(_.newInstance.say) // prints Hello B, Hello C

答案 2 :(得分:0)

可能更简单:

trait MyType{def myMethod:Unit}
class ActionInvoker[T <: MyType](parameter: T){
  def invoke:Unit = parameter.myMethod
}
class Inst1 extends MyType{def myMethod = println("Inst1 here")}
class Inst2 extends MyType{def myMethod = println("Inst2 here")}
val l:List[Class[_ <: MyType]] = List(classOf[Inst1], classOf[Inst2])
for(c <- l){
  new ActionInvoker(c.newInstance).invoke
}