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.

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?


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)
                                               ^

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]

36
Es gibt auch List.empty[Foo]eine dritte Alternative.
Kassens
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.