2017-01-31 34 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無數組 – slouc

+0

有趣的是,'Array()。isEmpty'工作:) – 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

編輯:可能這個答案是不正確的。但我在這裏保存它以顯示我如何嘗試調查此問題。對我來說,它看起來像編譯器中的一個錯誤。

答案是存在Array[T <: AnyRef] 字符串是AnyRefNothingAnyRef隱式轉換。

你怎麼能自己發現這個?

在的IntelliJ可以看到下isEmpty enter image description here

灰色下劃線這意味着該方法isEmpty不是陣列的方法,而是一個隱式的(一個上的一類方法,它具有從陣列的隱式轉換)。

現在,發現隱式轉換,只需點擊ctrl+q enter image description here

所以當你遵循它,你就會得到這一行的源代碼 -

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

這解釋了隱式轉換當T延伸AnyRef時,它位於陣列[T]上

所以回到我們的案例 - String <: AnyRef,但這並不適用於Nothing

+0

具有很多意義,非常感謝解釋!我不是IntelliJ的最大粉絲,但這是一個很酷的功能。 – user4601931

+1

這裏的推理是不正確的。 'Nothing' _is絕對是'AnyRef'的子類型。嘗試:'refArrayOps [Nothing](Array())。isEmpty' - 它工作得很好。 'y.isEmpty'隱含的原因遠不如此。 –

+0

@MichaelZajac你是什麼意思「更加可疑」? – user4601931