Scala泛型:使用恢复实际类型来调用另一个泛型函数

时间:2019-01-02 08:56:47

标签: scala generics

这似乎是一个人为的问题,但这是因为我已将其从更大的程序中简化了。

我在环境类中已经有一个通用方法:

class Environment {
    def obtain[T <: Element](param : Int)(implicit ctag : ClassTag[T]): Array[T] = { ... }
}

我也定义

abstract class Process[T <: Element : ClassTag] { 
    def run(input : Array[T]) : Array[_ <: Element]
}

和一些具体的课程

class Oxidation extends Process[Hydrogen] { ... }
class Reduction extends Process[Water] { ... }

现在,我想拥有一个Process集合并按顺序运行它们。这是我希望写的方式:

val myEnv = new Environment
val allProcesses : Seq[Process[_]] = Seq(new Oxidation, new Reduction)
allProcess.map(proc => 
    val material = myEnv.obtain[proc.*SPECIFIC TYPE HERE*](1)
    proc.run(material)
)

之所以不能将myEnv提供给proc(确实可以正确编译和执行),是因为我希望像这样优化程序:

val myEnv = new Environment
val allProcesses : Seq[Process[_]] = Seq(new Oxidation, new Reduction)
allProcess.map(proc => 
    val material = myEnv.obtain[proc.*SPECIFIC TYPE HERE*](1)
    proc.run(material)
    anotherProc.run(material)
    anotherProc2.run(material)
)

有任何线索吗?只要可以动态调用myEnv.obtain [someVariable],就可以重构程序的大部分内容。

我正在使用Scala 2.10.6。预先谢谢你!

1 个答案:

答案 0 :(得分:1)

您需要为每个单独的Process的TypeParameter使用ClassTag。 Process类已经需要将这样的TypeTag[T]隐式传递给其构造函数,您可以公开以下内容:

abstract class Process[T <: Element : ClassTag] {
  def ctag: ClassTag[T] = implicitly[ClassTag[T]]
  def run(input : Array[T]) : Array[_ <: Element] = { ... }
}

val myEnv = new Environment
val allProcesses: Seq[Process[_ <: Element]] = Seq(new Oxidation, new Reduction)

// This functions binds the type parameter of `proc` as `T`, so we can refer to it.
def doRun[T <: Element](proc: Process[T]) = {
  val material = myEnv.obtain[T](1)(proc.ctag)
  proc.run(material)
}
for (process ← allProcesses) yield doRun(process)