2013-08-27 18 views
3

我幾乎可以肯定,這個問題之前已經被問過了,但我錯過了正確的詞語來找到它。爲什麼Scala偶爾會回退到Java對象?

scala> Seq[Any](3, 3.4) 
res0: Seq[Any] = List(3, 3.4) 

scala> res0(1).getClass 
res1: Class[_] = class java.lang.Double 

scala> Seq(3, 3.4) 
res2: Seq[Double] = List(3.0, 3.4) 

scala> res2(1).getClass 
res3: Class[Double] = double 

爲什麼斯卡拉處理我Double輸入爲java.lang.Double一個Seq[Any]內,但它一直爲scala.DoubleSeq[AnyRef]工作時?有沒有辦法來防止這種行爲,而是總是使用Scala類型?

回答

7

斯卡拉的Double對應於Java的double,但如果需要可能會自動裝箱和取消裝箱,當它被自動裝箱時它會變成java.lang.Double。在實踐中,集合需要對原始變量進行自動裝箱。

如果未明確聲明類型,則根據分配給它們的值推斷您聲明的集合的類型。問題中兩個聲明的區別在於對於Seq(value1,value2,...)類型,推理嘗試查找「最佳」類型,並根據此類型(Scala Double)與Seq[Double]進行匹配,然後對value1,value2等進行了解釋。如果您明確聲明類型爲Seq[Any],則類型推理不會運行(因爲您自己給出類型),因此值value1,value2等不會被強制解釋爲固定類型。

由於Seq是一家集,原始數據是不允許的,必須autoboxed,所以Java的double無法適從,而java.lang.Double即可。試圖隱藏拳擊和取消裝箱的邏輯並透明地交換原語和對象並不起作用。實際上,在Seq[Any]中,每個元素可能是不同的類型,這意味着這種裝箱和拆箱在一般情況下無法工作(在您的示例中,res0(0).getClassInteger,而res2(0).getClass是Double)。

所以,基本上,如果你沒有明確地聲明類型,類型推理就會啓動並首先嚐試爲集合的所有元素找到一個通用類型,然後在集合類型中將所有元素轉換爲該類型參數明確指定,則不會發生此類事情,並且所有值的類型都被解釋爲「原始」。

+0

但是,例如'3'的文字是'Int <:AnyVal <:Any'。我一直在問的是'Seq [Any]'。所以乍一看,維護Scala類型不應該是一個問題。爲什麼拳擊變得必要? – Taig

+1

@泰格拳擊是需要的,因爲集合在對象上工作。 Scala試圖隱藏存在原始類型和對象的事實,但在JVM級別上,這種區別確實存在。由於Scala在JVM上運行,因此受到此限制。它試圖隱藏它,但並不總是可以的。 JVM沒有'AnyVal'的等價物,因此在集合中,層次結構只看起來像'java.lang.Integer <:Object'。 –

4

發生了什麼是拳擊。因爲第一個是Seq[Any],所以其中的任何原語都會以盒裝形式返回。在第二種情況下,由於類型爲Seq[Double],對成員的訪問將自動取消裝箱(但仍會將其存儲在Seq中)。

嘗試獲取原語的運行時類必然會導致各種問題。儘量不要使用getClass

相關問題