List
a 2 méthodes qui sont spécifiées pour ajouter un élément à une liste (immuable):
+:
(implémentation Seq.+:
), et::
(défini uniquement dans List
)+:
a techniquement une signature de type plus générale—
def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]
—Mais en ignorant l'implicite, qui selon le message doc nécessite simplement que That
soit List[B]
, les signatures sont équivalentes.
Quelle est la différence entre List.+:
et List.::
? S'ils sont en fait identiques, je suppose que +:
serait préférable d'éviter en fonction de l'implémentation concrète List
. Mais pourquoi une autre méthode publique a-t-elle été définie et quand le code client l'appellerait-il?
Il existe également un extracteur pour ::
dans la correspondance de motifs, mais je m'interroge sur ces méthodes particulières.
Voir aussi: concaténation de la liste Scala, ::: vs ++
La meilleure façon de déterminer la différence entre les deux méthodes est de le rechercher dans le code source.
source de ::
:
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
source de +:
:
override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match {
case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That]
case _ => super.+:(elem)(bf)
}
Comme vous pouvez le voir, pour List
, les deux méthodes font la même chose (le compilateur choisira List.canBuildFrom pour l'argument CanBuildFrom
).
Alors, quelle méthode utiliser? Normalement, on choisirait l'interface (+:
) Que l'implémentation (::
) Mais parce que List
est une structure de données générale dans les langages fonctionnels, il a ses propres méthodes qui sont largement utilisées . De nombreux algorithmes construisent le fonctionnement de List
. Par exemple, vous trouverez de nombreuses méthodes qui ajoutent des éléments uniques à List
ou appellent les méthodes pratiques head
ou tail
car toutes ces opérations sont O(1)
. Par conséquent, si vous travaillez localement avec un List
(à l'intérieur de méthodes ou de classes uniques), il n'y a aucun problème à choisir les méthodes spécifiques à List
. Mais si vous voulez communiquer entre les classes, c'est-à-dire que vous voulez écrire certaines interfaces, vous devez choisir l'interface Seq
plus générale.
+:
est plus générique, car il permet au type de résultat d'être différent du type de l'objet auquel il est appelé. Par exemple:
scala> Range(1,4).+:(0)
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)