在 Scala 中编写带有 ClassTag 和 AnyRef 约束的泛型函数

Writing a generic function with ClassTag and AnyRef constraints in Scala

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-s 对我来说有点黑魔法。

如何修复这段代码,使 sc.broadcast(期望 ClassTag)和 SizeEstimator.estimate(期望 AnyRef)都满意?

除了强制执行隐式 ClassTag 之外,您还可以将 T 定义为扩展 AnyRef 的类型。请注意,这会将您的 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

作为 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)
}