2010-05-27 12 views

Répondre

23

la raison Iterable n'a pas une méthode contains est parce que la façon dont il est défini peut avoir des conséquences directes sur vari ance. Fondamentalement, il existe deux signatures de type qui ont du sens pour cela:

def contains(v: Any): Boolean 
def contains(v: A): Boolean 

La seconde définition a augmenté la sécurité de type. Cependant, A, qui est le paramètre de type de collection, apparaît dans une position à contre-sens, ce qui force la collection à être invariante. Il pourrait être définie comme ceci:

def contains[B >: A](v: B): Boolean 

mais qui n'offrirait une amélioration par rapport à la première signature, en utilisant Any. En conséquence, immutable.Seq est co-variant et utilise la première signature, tandis que immutable.Set est invariant et utilise la deuxième signature.

+0

Remarque: 'contains' ** est ** implémenté en utilisant la signature' contains [A1>: A] (elem: A1) 'dans' SeqLike' (au moins dans Scala 2.11.8). Je ne pense pas que ce soit le même que d'utiliser 'Any' - il place des contraintes sur le type' B' - vous pouvez passer 'Any', mais vous ne pouvez pas passer un type qui est connu pour être non apparenté. – Suma

+0

@Suma Bien sûr, vous pouvez. Allez-y et essayez. Si vous passez un type non apparenté, 'A1' sera supposé être le supertype commun. Et parce que tout est descendant de 'Any', alors tous les types ont un supertype commun entre eux. –

+0

Vous avez raison. Y a-t-il une raison pour laquelle la signature dans la bibliothèque est telle qu'elle est, et non avec Any, comme vous écrivez, alors? – Suma

5

Je ne sais pas pourquoi contains n'est pas défini sur Iterable ou TraversableOnce, mais vous pouvez facilement définir vous-même:

class TraversableWithContains[A](underlying: TraversableOnce[A]) { 
    def contains(v: Any): Boolean = 
    underlying.exists(_ == v) 
} 
implicit def addContains[A](i: Iterable[A]) = new TraversableWithContains(i) 

et l'utiliser comme si elle était définie sur Iterable:

val iterable: Iterable[Int] = 1 to 4 
assert(iterable.contains(3)) 
assert(!iterable.contains(5))