Scala: Nil vs Liste ()


128

Dans Scala, y a-t-il une différence entre Nilet List()?

Sinon, lequel est le plus idiomatique du style Scala? À la fois pour créer de nouvelles listes vides et pour faire correspondre des modèles sur des listes vides.

Réponses:


188
scala> println (Nil == List())
true

scala> println (Nil eq List())
true

scala> println (Nil equals List())
true

scala> System.identityHashCode(Nil)
374527572

scala> System.identityHashCode(List())
374527572

Nil est plus idiomatique et peut être préféré dans la plupart des cas. Des questions?


11
Vous pourriez mentionner que Nilc'est plus idiomatique.
Rex Kerr

6
Ajout de System.identityHashCode pour clarifier ce que "eq" dit déjà - ils sont le même objet.
James Iry

18
De plus, Nil fait directement référence à un objet, alors que List () est un appel de méthode.
Jean-Philippe Pellet

6
N'est-ce pas List[A]()(pas Nil) nécessaire comme valeur d'accumulateur pour foldLeft? Exemple - scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)Utiliser Nilici comme accumulateur ne fonctionnerait pas.
Kevin Meredith

6
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Raul

85

L'utilisateur inconnu a montré que la valeur d'exécution des deux Nilet était List()la même. Cependant, leur type statique n'est pas:

scala> val x = List()
x: List[Nothing] = List()

scala> val y = Nil
y: scala.collection.immutable.Nil.type = List()

scala> def cmpTypes[A, B](a: A, b: B)(implicit ev: A =:= B = null) = if (ev eq null) false else true
cmpTypes: [A, B](a: A, b: B)(implicit ev: =:=[A,B])Boolean

scala> cmpTypes(x, y)
res0: Boolean = false

scala> cmpTypes(x, x)
res1: Boolean = true

scala> cmpTypes(y, y)
res2: Boolean = true

Ceci est particulièrement important lorsqu'il est utilisé pour déduire un type, comme dans l'accumulateur d'un repli:

scala> List(1, 2, 3).foldLeft(List[Int]())((x, y) => y :: x)
res6: List[Int] = List(3, 2, 1)

scala> List(1, 2, 3).foldLeft(Nil)((x, y) => y :: x)
<console>:10: error: type mismatch;
 found   : List[Int]
 required: scala.collection.immutable.Nil.type
       List(1, 2, 3).foldLeft(Nil)((x, y) => y :: x)
                                               ^

Je ne comprends pas pourquoi 2 :: Nil fonctionne mais pas l'accumulateur de repli y :: x
FUD

2
@FUD Eh bien, y :: x ça marche. Le problème est que le type qu'il renvoie n'est pas le type attendu. Il revient List[Int], tandis que le type attendu est soit List[Nothing]ou Nil.type(je pense que le premier, mais peut-être le second).
Daniel C. Sobral

27

Comme le montre la réponse de l'utilisateur inconnu, il s'agit du même objet.

Idiomatiquement Nil devrait être préféré car c'est joli et court. Il y a une exception cependant: si un type explicite est nécessaire pour une raison quelconque, je pense

List[Foo]() 

est mieux que

Nil : List[Foo]

36
Il y a aussi List.empty[Foo]une troisième alternative.
kassens
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.