如何使这个特性协变

时间:2013-03-26 10:41:21

标签: scala generics covariance typeclass

我想制作以下特征协变,知道DistTraversableLike在其两个类型参数中都是协变的:

trait TraversableNumOps[T, Repr] extends DistTraversableLike[T, Repr] {

  private def min(a: T, b: T)(implicit num: Numeric[T]) =
    if (num.compare(a, b) <= 0) a else b
  private def max(a: T, b: T)(implicit num: Numeric[T]) =
    if (num.compare(a, b) > 0) a else b

  def maxD(implicit num: Numeric[T]): Option[T] =
    reduceD((a, b) => if (a >= b) a else b)
  def minD(implicit num: Numeric[T]): Option[T] =
    reduceD((a, b) => if (a < b) a else b)
  def sumD(implicit num: Numeric[T]): Option[T] =
    reduceD(_ + _)
  def productD(implicit num: Numeric[T]): Option[T] =
    reduceD(_ * _)

}

然而,我没有能够在没有破坏它的情况下管理它。问题是我想支持Numeric[T],这在T中是不协变的。

如何在TRepr中修改此特性以变为协变?

1 个答案:

答案 0 :(得分:2)

Repr应该不是问题,因为它不会出现在任何方法参数的类型中。

然而,T确实发生在逆变位置。 您可以在private[this]min上添加max修饰符来修改此问题。这将确保这些方法仅在当前对象中使用,并且编译器可以在当前对象的范围内检查方差违规。

对于maxD和其他人,请考虑让他们采用超级T

def maxD[U >: T](implicit num: Numeric[U]): Option[U]

这解决了方差问题,因为无法使用U的超类型T并违反方差(例如,您无法将其分配给对象的字段,因为{{1 }}不能有TraversableNumOps)类型的字段。