web-dev-qa-db-fra.com

Quelle est la différence entre `::` et `+:` pour l'ajout à une liste)?

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?

Éditer

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

43
Mechanical snail

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.

36
kiritsuku

+: 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)
11
Kim Stebel