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.

Bart
la source

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?

Utilisateur inconnu
la source
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)
                                               ^
Daniel C. Sobral
la source
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]
James Iry
la source
36
Il y a aussi List.empty[Foo]une troisième alternative.
kassens