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.