2017-05-18 2 views
2

Y a-t-il un moyen de mélanger le trait ordonné pour un générique covariant?Implémenter un trait ordonné avec un générique covariant

J'ai le code suivant:

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

    def id: Int 

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

où je dois T covariant et je voudrais REQUISITIONNES aussi. La version ci-dessus donne le "type covariant en erreur de position contravariante".

Répondre

3

Vous ne pouvez pas utiliser Ordered avec un type covariant parce qu'elle exige un type générique dans une position contravariant. Au lieu de cela, vous devez utiliser un Ordering implicite défini dans le compagnon objectera

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 
    } 
    } 
} 

Toute fonction raisonnable qui compare l'objet doit être prendre dans une instance de commande pour les objets qu'il compare, et beaucoup le font implicitement. Par exemple

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

Ordered[A] est invariant dans A. The old documentation for this trait explains why:

Un trait pour les données totalement ordonnées. Notez que depuis la version 2006-07-24 ce trait n'est plus covariant dans un. Il est important que la méthode equals pour une instance de Ordered [A] soit cohérente avec la méthode de comparaison. Cependant, en raison des limitations inhérentes à la sémantique d'effacement de type, il n'y a aucun moyen raisonnable de fournir une implémentation d'égalité par défaut pour les instances de Ordered [A]. Par conséquent, si vous devez être en mesure d'utiliser l'égalité sur une instance de Ordered [A], vous devez le fournir vous-même lors de l'initialisation ou de l'instanciation. Il est important que la méthode hashCode d'une instance de Ordered [A] soit cohérente avec la méthode de comparaison. Cependant, il n'est pas possible de fournir une implémentation par défaut sensée. Par conséquent, si vous avez besoin de pouvoir calculer le hachage d'une instance de Ordered [A], vous devez le fournir vous-même lorsque vous dirigez ou instanciez.

Cela signifie que si vous voulez utiliser Ordered[A] vous aurez explicitement fournir une implémentation de compare pour les sous-types de Foo.

Une solution peut être fait avec un implicite Ordering[A]:

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