Scala: zero vs lista ()

130

Czy w Scali jest jakaś różnica między Nili List()?

Jeśli nie, to który z nich jest bardziej idiomatyczny w stylu Scala? Zarówno do tworzenia nowych pustych list, jak i dopasowywania wzorców na pustych listach.

Bart
źródło

Odpowiedzi:

190
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

Brak jest bardziej idiomatyczny i może być preferowany w większości przypadków. Pytania?

nieznany użytkownik
źródło
11
Można wspomnieć, że Niljest to bardziej idiomatyczne.
Rex Kerr
6
Dodano System.identityHashCode, aby wyjaśnić, co już mówi „eq” - to ten sam obiekt.
James Iry
18
Poza tym Nil bezpośrednio odwołuje się do obiektu, podczas gdy List () jest wywołaniem metody.
Jean-Philippe Pellet
6
Czy nie jest List[A]()(nie Nil) konieczne jako wartość akumulatora dla foldLeft? Przykład - scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)użycie Niljako akumulatora tutaj nie zadziała.
Kevin Meredith
6
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Raul
86

Użytkownik nieznany wykazał, że wartości czasu wykonywania obu Nili List()są takie same. Jednak ich statyczny typ nie jest:

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

Ma to szczególne znaczenie, gdy jest używane do wnioskowania typu, na przykład w akumulatorze fałdy:

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
źródło
nie rozumiem, dlaczego 2 :: Nil działa, ale nie akumulator fold y :: x
FUD
2
@FUD Cóż, y :: x robi pracę. Problem polega na tym, że typ, który zwraca, nie jest typem oczekiwanym. Powraca List[Int], podczas gdy oczekiwany typ to albo List[Nothing]lub Nil.type(myślę, że pierwszy, ale może drugi).
Daniel C. Sobral
27

Jak pokazuje odpowiedź nieznanego użytkownika, są to ten sam obiekt.

Idiomatycznie Nil powinno być preferowane, ponieważ jest ładne i krótkie. Jest jednak wyjątek: jeśli z jakiegokolwiek powodu potrzebny jest jawny typ

List[Foo]() 

jest ładniejszy niż

Nil : List[Foo]
James Iry
źródło
36
Istnieje również List.empty[Foo]trzecia alternatywa.
kassens