首页 > 解决方案 > 如何在 scala 中初始化泛型变量

问题描述

众所周知,我们可以T在 C++ 中初始化一个模板参数对象。

template <typename T>
struct Cont{
    T t;
}

我想在 scala 中做同样的事情,所以我编写了以下代码。还有一些其他类可以扩展Evaluator,并且EvaluateComponent类似于包装器。我可以写代码new EvaluateComponent[BinaryClassificationEvaluator].evaluate(df)

abstract class Evaluator extends Serializable{
  var predCol = "prediction"
  var trueCol = "label"
  def evaluate(dataset: DataFrame) : String
  def evaluateRDD(dataset: RDD[(Double, Double)]) : String
}

class EvaluateComponent[E <: Evaluator : ClassTag] {
  val evaluator = new E
}

class BinaryClassificationEvaluator extends Evaluator {
  ...
}

但是它不会编译错误class type required but E found。该帖子没有解决我的问题,因为我希望初始化评估器。

标签: scalagenerics

解决方案


Scala 中的限制与 Java 相同——泛型类型在编译时被删除,并且不能直接访问像 C++ 这样的类构造函数。但这可以通过Java反射来完成:

abstract class Evaluator extends Serializable{}

class EvaluateComponent[E <: Evaluator : ClassTag] {
  val evaluator = implicitly[ClassTag[E]].runtimeClass.newInstance().asInstanceOf[E]
}

class BinaryClassificationEvaluator extends Evaluator {}

new EvaluateComponent[BinaryClassificationEvaluator].evaluator // Returns a BinaryClassificationEvaluator

话虽这么说,但这并不意味着这是一个好方法。要点是:

  • 泛型参数中传递的类必须具有默认构造函数。如果没有,将会有运行时异常
  • 反射比普通代码慢

不同的语言程序不同的心态。最好在 Scala 中使用类型类来实现这一点,但这是另一个主题。


编辑:

Class.newInstance现在已弃用。Class.getDeclaredConstructor().newInstance()改为使用


推荐阅读