使用协变泛型实现有序特征

时间:2017-05-18 20:09:02

标签: scala generics covariance

是否有一种混合使用协变特征的有序特征?

我有以下代码:

trait Foo[+T  <: Foo[T]] extends Ordered[T] {

  def id: Int

  override def compare(that : T) : Int = {
    this.id compare that.id
  }    
}

我需要T协变的地方,并希望下令工作。上面的版本给出了逆变位置误差&#34;协变类型&#34;。

2 个答案:

答案 0 :(得分:3)

您不能将Ordered与协变类型一起使用,因为它需要在逆变位置使用泛型类型。相反,您应该使用随播对象

中定义的隐式Ordering
trait Foo[+T] {
  def id: Int

}

object Foo {
  implicit def fooOrdering[A <: Foo[_]]: Ordering[A] = {
    new Ordering[A] {
      override def compare(x: A, y: A): Int = x.id compare y.id
    }
  }
}

比较对象的任何合理函数都应该在它正在比较的对象的Ordering实例中,并且许多隐式地执行。例如

case class F(id: Int) extends Foo[Int]
case class G(id: Int) extends Foo[Int]

List(F(1), F(2), F(5), F(3), G(12)).max // = G(12)

答案 1 :(得分:1)

{p> Ordered[A]A中不变。 The old documentation for this trait explains why

  

完全有序数据的特征。请注意,自2006-07-24版本以来,此特征不再具有协变性。重要的是,Ordered [A]实例的equals方法与compare方法一致。但是,由于类型擦除语义中固有的限制,没有合理的方法为Ordered [A]的实例提供相等的默认实现。因此,如果您需要能够在Ordered [A]的实例上使用相等,则必须在iniririting或实例化时自己提供。重要的是,Ordered [A]实例的hashCode方法与compare方法一致。但是,不可能提供合理的默认实现。因此,如果您需要能够计算Ordered [A]实例的哈希值,则必须在启用或实例化时自行提供。

这意味着如果您想使用Ordered[A],则明确必须为compare的子类型提供Foo的实施。

可以使用隐式Ordering[A]

完成解决方法
implicit def ord[A <: Foo[A]] = new math.Ordering[A] {
  override def compare(a: A, b: A) = a.id compare b.id
}