2017-01-31 13 views
3

Вопрос не о как для проверки массива для пустоты (arr.length == 0 делает это отлично). Скорее всего мой вопрос, почемуТестирование массива для пустоты в Scala

scala> Array().isEmpty 
res1: Boolean = true 

работы и

scala> val x = Array[String]() 
x: Array[String] = Array() 
scala> x.isEmpty 
res2: Boolean = true 

работы, но

scala> val y = Array() 
y: Array[Nothing] = Array() 

scala> y.isEmpty 
<console>:13: error: value isEmpty is not a member of Array[Nothing] 
     y.isEmpty 
     ^

не?

+3

См. Http://stackoverflow.com/questions/5843001/why-does-map-filter-not -work-with-a-array-of-nothing – slouc

+0

Забавный, 'Array(). isEmpty' works :) – Dima

+0

Кажется, что' Array(). isEmpty' работает, потому что 'Array()' еще не было выведено как пустой, поэтому он берет 'Predef.refArrayOps'. –

ответ

3

Как @MichaelZajac указывает, Nothing является подтипом все (его аналог Any является супертипом всего). В частности, это также подтип AnyRef. На самом деле существует еще более общий genericArrayOps, который вообще не имеет привязки к типу (например, Array[Any]().isEmpty работ)! Неявное преобразование, позволяющее вам использовать isEmpty, должно быть, но, конечно же, это не так, хотя явное обращение к конвертации в порядке.

link @slouc дает ответ, а именно, что компилятор Scala рассматривает Nothing особым образом при выполнении неявного разрешения, поскольку Nothing по умолчанию нижней границы для типа при выполнении вывода типа.

Теперь почему именно было бы желательно, чтобы Nothing не учитывался в неявном разрешении?Что ж, сложная вещь о Nothing снова заключается в том, что это подтип всего. Это означает, что если в любой точке Scala указывается тип Nothing, каждое неявное преобразование сразу станет действительным. Это может скрыть ошибку типа (у вас никогда не должно быть экземпляра Nothing, но когда Nothing станет Int ... хорошо, кто скажет?). (Примечание. Мне бы очень хотелось, чтобы кто-то, кто на самом деле взломал компилятор, вскочил и подтвердил/отклонил/уточнил об этом)

1

EDIT: возможно, этот ответ неверен. Но я читаю его здесь, чтобы показать, как я попытался расследовать эту проблему. Для меня это похоже на ошибку в компиляторе.

Ответ неявное преобразование, которое существует для Array[T <: AnyRef] строки является AnyRef, Nothing не AnyRef.

Как вы могли бы открыть это самостоятельно?

В IntelliJ вы можете увидеть серое подчеркивание под isEmpty enter image description here

Это означает, что метод isEmpty не метод Array, но неявное (метод по классу, который имеет неявное преобразование из массива).

Теперь, чтобы открыть неявное преобразование, просто нажмите ctrl+q enter image description here

Так что, когда вы будете следовать, вы получите в этой строке в исходном коде -

implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs) 

Это объясняет, что неявное преобразование находится на массиве [T], когда T extends AnyRef

Итак, вернемся к нашему делу - String <: AnyRef, но это не имеет места для Nothing

+0

Делает много смысла, спасибо за объяснение! Я не самый большой поклонник IntelliJ, но это классная функция. – user4601931

+1

Это рассуждение здесь неверно. 'Nothing' _is абсолютно_ подтип' AnyRef'. Попробуйте: refArrayOps [Nothing] (Array()). IsEmpty' - он работает отлично. Причина, по которой имплицитное значение не срабатывает для 'y.isEmpty', гораздо более сомнительно, чем это. –

+0

@MichaelZajac Что вы подразумеваете под «гораздо более сомнительным»? – user4601931