Scala: Nil vs List ()

128

Gibt es in Scala überhaupt einen Unterschied zwischen Nilund List()?

Wenn nicht, welcher ist der idiomatischere Scala-Stil? Sowohl zum Erstellen neuer leerer Listen als auch zum Mustervergleich für leere Listen.

Bart
quelle

Antworten:

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 ist idiomatischer und kann in den meisten Fällen bevorzugt werden. Fragen?

Benutzer unbekannt
quelle
11
Man könnte erwähnen, dass Nildas idiomatischer ist.
Rex Kerr
6
System.identityHashCode wurde hinzugefügt, um zu verdeutlichen, was "eq" bereits sagt - es handelt sich um dasselbe Objekt.
James Iry
18
Außerdem verweist Nil direkt auf ein Objekt, während List () ein Methodenaufruf ist.
Jean-Philippe Pellet
6
Ist ein Akkumulatorwert für foldLeft nicht List[A]()(nicht Nil) erforderlich? Beispiel - Die scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)Verwendung Nilals Akkumulator hier würde nicht funktionieren.
Kevin Meredith
6
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Raul
84

Unbekannter Benutzer hat gezeigt, dass der Laufzeitwert von beiden Nilund List()gleich ist. Ihr statischer Typ ist jedoch nicht:

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

Dies ist von besonderer Bedeutung, wenn es verwendet wird, um auf einen Typ zu schließen, z. B. im Akkumulator einer Falte:

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
quelle
Ich verstehe nicht, warum 2 :: Nil funktioniert, aber nicht Fold's Akkumulator y :: x
FUD
2
@FUD Nun, y :: x funktioniert . Das Problem ist, dass der zurückgegebene Typ nicht der erwartete Typ ist. Es kehrt zurück List[Int], während der erwartete Typ entweder List[Nothing]oder ist Nil.type(ich denke der erstere, aber vielleicht der letztere).
Daniel C. Sobral
27

Wie die Antwort des unbekannten Benutzers zeigt, handelt es sich um dasselbe Objekt.

Idiomatisch sollte Nil bevorzugt werden, weil es schön und kurz ist. Es gibt jedoch eine Ausnahme: Wenn aus irgendeinem Grund ein expliziter Typ benötigt wird, denke ich

List[Foo]() 

ist schöner als

Nil : List[Foo]
James Iry
quelle
36
Es gibt auch List.empty[Foo]eine dritte Alternative.
Kassens