Scala: Zero vs List ()

128

Em Scala, existe alguma diferença entre Nile List()?

Se não, qual é o estilo Scala mais idiomático? Tanto para criar novas listas vazias quanto para correspondência de padrões em listas vazias.

Bart
fonte

Respostas:

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

Nada é mais idiomático e pode ser preferido na maioria dos casos. Questões?

Usuário desconhecido
fonte
11
Você poderia mencionar que Nilé mais idiomático.
Rex Kerr
6
Adicionado System.identityHashCode para esclarecer o que "eq" já diz - eles são o mesmo objeto.
James Iry
18
Além disso, Nil faz referência direta a um objeto, enquanto List () é uma chamada de método.
Jean-Philippe Pellet
6
Não é necessário List[A]()(não Nil) como um valor acumulador para foldLeft? Exemplo - scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)Usar Nilcomo acumulador aqui não funcionaria.
Kevin Meredith
6
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Raul
84

Usuário desconhecido mostrou que o valor do tempo de execução de ambos Nile List()é o mesmo. No entanto, seu tipo estático não é:

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

Isso é de particular importância quando usado para inferir um tipo, como no acumulador de uma dobra:

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
fonte
eu não entendo por 2 :: Nil funciona, mas não dobra do acumulador y :: x
FUD
2
@FUD Bem, y :: x faz o trabalho. O problema é que o tipo retornado não é o tipo esperado. Ele retorna List[Int], enquanto o tipo esperado é um List[Nothing]ou Nil.type(acho que o primeiro, mas talvez o último).
Daniel C. Sobral
27

Como mostra a resposta do usuário desconhecido, eles são o mesmo objeto.

Linguisticamente Nil deve ser preferido, porque é agradável e curto. Há uma exceção: se um tipo explícito for necessário por qualquer motivo que eu ache

List[Foo]() 

é melhor do que

Nil : List[Foo]
James Iry
fonte
36
Há também List.empty[Foo]como uma terceira alternativa.
Kassens 13/05