Scala: Nil vs List ()

128

В Scala есть ли вообще разница между Nilи List()?

Если нет, то какой из них более идиоматический стиль Scala? Как для создания новых пустых списков, так и для сопоставления с образцом в пустых списках.

Барт
источник

Ответы:

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 более идиоматичен и в большинстве случаев может быть предпочтительнее. Вопросы?

Пользователь неизвестен
источник
11
Вы могли бы упомянуть, что Nilэто более идиоматично.
Рекс Керр,
6
Добавлен System.identityHashCode, чтобы прояснить, что уже говорит "eq" - это один и тот же объект.
Джеймс Айри
18
Кроме того, Nil напрямую ссылается на объект, а List () - это вызов метода.
Жан-Филипп Пелле,
6
Разве List[A]()(не Nil) необходимо использовать значение аккумулятора для foldLeft? Пример - scala> Map(1 -> "hello", 2 -> "world").foldLeft(List[String]())( (acc, el) => acc :+ el._2) res1: List[String] = List(hello, world)использование Nilв качестве аккумулятора здесь не сработает.
Кевин Мередит
6
Map(1 -> "hello", 2 -> "world").foldLeft(Nil: List[String])( _ :+ _._2)
Рауль
85

Пользователь unknown показал, что значения времени выполнения для обоих Nilи List()одинаковы. Однако их статический тип не является:

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

Это особенно важно, когда оно используется для вывода типа, например, в аккумуляторе свертки:

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)
                                               ^
Дэниел С. Собрал
источник
Я не понимаю, почему 2 :: Nil работает, но не складывает аккумулятор y :: x
FUD
2
@FUD Ну, y :: x делает работу. Проблема в том, что возвращаемый тип не является ожидаемым. Он возвращается List[Int], в то время как ожидаемый тип - List[Nothing]или Nil.type(я думаю, первое, но, возможно, второе).
Дэниел С. Собрал,
27

Как показывает ответ пользователя unknown, это один и тот же объект.

Идиоматически следует предпочесть Nil, потому что он красивый и короткий. Однако есть исключение: если явный тип необходим по какой-то причине, я думаю

List[Foo]() 

лучше чем

Nil : List[Foo]
Джеймс Айри
источник
36
Есть еще и List.empty[Foo]третья альтернатива.
kassens