以下代碼在運行時編譯正常但崩潰(用scala 2.9.2測試)。Scala:List [Double]與列表[Double]的列表[Int]有什麼不同?
object Test {
def fun(x:Double) : Double = { 1.234 * x }
def main(args: Array[String]) {
val l1 = List(1.0, 2.0, 3.0)
val lfun1 = l1 map fun
println(lfun1)
val l2 = List(1, 2, 3).asInstanceOf[List[Double]]
val lfun2 = l2 map fun // <--- crashes
println(lfun2)
}
}
輸出:
List(1.234, 2.468, 3.702)
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
at scala.runtime.BoxesRunTime.unboxToDouble(BoxesRunTime.java:114)
at Test$$anonfun$2.apply(Covariance.scala:11)
at scala.collection.immutable.List.map(List.scala:273)
at Test$.main(Covariance.scala:11)
at Test.main(Covariance.scala)
參見下面的REPL輸出的更多細節。
我來自Java並想學習Scala,那麼有人可以向我解釋爲什麼它崩潰的原因以及爲什麼編譯器無法檢測到它?我認爲這與「視圖」(Int與Double)或「協方差」(列表[Int]爲列表[Double])有關,但我沒有理解。
這裏是斯卡拉REPL個別輸出:
scala> def fun(x:Double) : Double = { 1.234 * x }
fun: (x: Double)Double
scala> val l1 = List(1.0, 2.0, 3.0)
l1: List[Double] = List(1.0, 2.0, 3.0)
scala> val lfun1 = l1 map fun
lfun1: List[Double] = List(1.234, 2.468, 3.702)
scala> println(lfun1)
List(1.234, 2.468, 3.702)
scala> val l2 = List(1, 2, 3).asInstanceOf[List[Double]]
l2: List[Double] = List(1, 2, 3)
scala> val lfun2 = l2 map fun
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
at scala.runtime.BoxesRunTime.unboxToDouble(Unknown Source)
at $anonfun$1.apply(<console>:9)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:233)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:76)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:233)
at scala.collection.immutable.List.map(List.scala:76)
at .<init>(<console>:9)
at .<clinit>(<console>)
at .<init>(<console>:11)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
at java.lang.Thread.run(Thread.java:745)
是Java允許的抱怨編譯器沒有這樣的投(甚至沒有'名單''到列表
總而言之:有沒有另外一種解釋不依賴於Java內部,而只依賴於Scala語言規範本身? –
爲了響應你的編輯:我剛剛意識到'val l3 = List(1,2,3)'甚至在嘗試'l3 map fun'時會產生*編譯時錯誤*,就像它應該那樣!所以我現在看到,正如你所指出的那樣,所有這些麻煩的核心在於「asInstanceOf」。所以我可能應該儘可能避免使用'asInstanceOf'(並且只有在我*絕對*確保所有元素都被轉換爲*超類型時,纔會在另一個視圖中使用它) –