Следующий код компилируется нормально, но сбой во время выполнения (протестирован с помощью scala 2.9.2).Scala: как List [Double] отличается от List [Int], который вызывается в List [Double]?
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 versus Double) или «ковариации» (List [Int] как List [Double]), но я не понимаю.
Вот индивидуальный выход в Scala РЕПЛ:
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 не допускает такой бросок (даже не '' List в 'Список
Вкратце сформулировано коротко: есть ли еще одно объяснение, которое * не * полагается на внутренние элементы Java, но только на самой спецификации языка Scala? –
В ответ на ваше редактирование: я просто понял, что 'val l3 = List (1, 2, 3)' даже дает ошибку времени компиляции * при попытке «l3 map fun», как и должно быть! Поэтому я вижу теперь, что в основе всей этой проблемы лежит «asInstanceOf», как указано вами. Поэтому я, вероятно, должен избегать 'asInstanceOf', когда это возможно (и использовать его только в коллекциях, если я * absoluetly * уверен, что все элементы будут переданы в супертип *, а не только в другое представление) –