Scala: Nil vs List ()

128

En Scala, ¿hay alguna diferencia entre Nily List()?

Si no, ¿cuál es el estilo de Scala más idiomático? Tanto para crear nuevas listas vacías como para la coincidencia de patrones en listas vacías.

Bart
fuente

Respuestas:

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 es más idiomático y se puede preferir en la mayoría de los casos. Preguntas?

usuario desconocido
fuente
11
Se podría mencionar que Niles más idiomático.
Rex Kerr
66
Se agregó System.identityHashCode para aclarar lo que ya dice "eq": son el mismo objeto.
James Iry
18
Además, Nil hace referencia a un objeto directamente, mientras que List () es una llamada al método.
Jean-Philippe Pellet
66
¿No es List[A]()(no Nil) necesario como valor acumulador para foldLeft? Ejemplo: el scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)uso Nilcomo acumulador aquí no funcionaría.
Kevin Meredith
66
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Raúl
85

Usuario desconocido ha demostrado que el valor de tiempo de ejecución de ambos Nily List()son los mismos. Sin embargo, su tipo estático no es:

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

Esto es de particular importancia cuando se usa para inferir un tipo, como en el acumulador de un pliegue:

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
fuente
no entiendo por qué 2 :: Nil funciona pero no el acumulador de pliegues y :: x
FUD
2
@FUD Bueno, y :: x hace el trabajo. El problema es que el tipo que devuelve no es el tipo esperado. Regresa List[Int], mientras que el tipo esperado es List[Nothing]o Nil.type(creo que el primero, pero tal vez el último).
Daniel C. Sobral
27

Como muestra la respuesta del usuario desconocido, son el mismo objeto.

Idiomáticamente, se debe preferir Nil porque es agradable y corto. Sin embargo, hay una excepción: si se necesita un tipo explícito por cualquier razón, creo

List[Foo]() 

es mejor que

Nil : List[Foo]
James Iry
fuente
36
También hay List.empty[Foo]una tercera alternativa.
Kassens