在Scala中使用ClassTag和AnyRef约束编写泛型函数

时间:2017-06-20 20:07:43

标签: scala generics type-bounds

Apache SparkContext有一个方法:

def broadcast[T: ClassTag](value: T): Broadcast[T]

我正在尝试编写一个分析数据的包装器(现在它只是尝试记录大小)并调用原始方法:

def broadcast[T: ClassTag](value: T): Broadcast[T] = {
  val sizeEst = SizeEstimator.estimate(value)
  log.debug(s"Broacasting $sizeEst bytes of data")
  sc.broadcast(value)
}

org.apache.spark.util.SizeEstimator需要AnyRef,因此我收到错误消息。我对Scala并不是特别有经验,所以ClassTag - 对我来说有点黑魔法。

如何修复此代码段,以便sc.broadcast(期望ClassTag)和SizeEstimator.estimate(期望AnyRef)都满意?< / p>

2 个答案:

答案 0 :(得分:2)

除了强制执行隐式T之外,您还可以将AnyRef定义为扩展ClassTag的类型。请注意,这会将您的boradcast版本的使用限制为仅广播AnyRef的子类(基本上都是非基元,请参阅http://docs.scala-lang.org/tutorials/tour/unified-types.html):

def broadcast[T <: AnyRef : ClassTag](value: T): Broadcast[T] = {
  val sizeEst = SizeEstimator.estimate(value)
  log.debug(s"Broacasting $sizeEst bytes of data")
  sc.broadcast(value)
}

broadcast(List(1,2,3)) // compiles
broadcast("str")       // compiles
broadcast(1)           // does not compile, because Int does not extend AnyRef

答案 1 :(得分:2)

作为Tzach Zohar答案的替代方案:由于通用T无论如何都会被装箱,这实际上是asInstanceOf不存在任何问题的罕见情况:

def broadcast[T: ClassTag](value: T): Broadcast[T] = {
  val sizeEst = SizeEstimator.estimate(value.asInstanceOf[AnyRef])
  log.debug(s"Broacasting $sizeEst bytes of data")
  sc.broadcast(value)
}