Как правильно использовать asInstanceOf в Scala

Я играл с базовыми типами данных Scala. Я заметил, что класс scala.Any определяет метод asInstanceOf[T0]: T0 из здесь API имеет то, что он может "Передавать объект получателя типа T0". Используя этот метод в качестве отправной точки, я хотел исследовать кастинг в Scala. Кроме того, я просмотрел stackoverflow для других вопросов по этой теме, и я придумал this Имея эту информацию, я написал глупую программу.

         package com.att.scala
         import com.att.scala.Sheltie

         object Casting {

             //def foo(x: String){ 
             def foo(x: Int) {
              println("x is " + x)
             //if(x.isInstanceOf[String])
              if(x.isInstanceOf[Int])
                 println("Int x is " + x)
                //println("String x is " + x)
             }

            def entry() {
               //val double: Any = 123.123
               val double: Double = 123.23
               val int = double.asInstanceOf[Int] //exception expected here
               //val str: String = "123"
               foo(int) 
             }

         }

Моя цель - понять, что происходит (и почему) в следующих случаях:  1) литье из любого типа в Int. 2) литье из двойного типа в Int 3) литье из String в Int

  • В первом случае у меня было время выполнения ClasscastException, как показано ниже, когда я запускал программу as-com.att.scala.Casting.entry. Исключение указано ниже:

    java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source) at com.att.scala.Casting$.entry(Casting.scala:17)

  • Во втором случае получается следующий результат: int - 123 x - 123 Int x - 123

В этом случае предполагается, что код создает ClasscastException, но это не так. Это мое беспокойство.

  1. В третьем случае я получаю classcastexception:

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer at scala.runtime.BoxesRunTime.unboxToInt(Unknown Source) at com.att.scala.Casting$.entry(Casting.scala:20)

В этом примере моя цель - перейти к самым основам кастинга в Scala. Я знаю, что этот пример никоим образом не является примером для реального мира, но я пытался заставить свою голову обернуться вокруг основ.

Ответ 1

Java (и Scala) позволяет использовать примитив double to int (в Scala case, double to int). С другой стороны, вы не можете отбрасывать java.lang.Double до java.lang.Int.

Когда вы объявляете double как Any, вы явно просите компилятор забыть, что вы дали ему double. Поэтому, чтобы поддерживать интерфейс Any, компилятор сохраняет значение в виде двойного двойного (т.е. java.lang.Double).

Поведение кажется запутанным, но это не ошибка. Согласно §12.1 Scala Language Spec:

Тест x.asInstanceOf [T] обрабатывается специально, если T - числовое значение типа (§12.2). В этом случае приведение будет переведено в приложение метода преобразования x.toT(§12.2.1).

Ответ 2

Я думаю, вы путаете термины "cast" и "convert".

Стандартные методы преобразования начинаются с to, например. 20d.toInt преобразует значение 20 типа Double значение 20 типа Int.

asInstanceOf, с другой стороны, является методом литья специального типа. Все, что он делает, сообщает компилятору, что значение имеет тип, указанный в его параметре, если во время выполнения значение, которое вы вызываете этот метод, не соответствует тому, что вы указали в параметре типа, вы получите вызванное исключение. То есть в a.asInstanceOf[B] предоставленное значение a должно быть типа B или наследовать от него, иначе вы получите исключение.

Ответ 3

Просто сделайте больше тестов (скомпилированных и запущенных), я думаю, это может быть из одной ошибки asInstanceOf, это не будет делать.

Последняя строка дает мне ошибку компиляции:

Предупреждение: (46, 38) бесплодный тест типа: значение типа Int также не может быть S     println (listTemp2 (1).isInstanceOf [S])//не будет компилировать

                                 ^ 

val listOfS = Some(List(S("i1", "k1", "s1"), S("i2", "k2", "s2")))
val listTemp:Seq[K] = listOfS.get.asInstanceOf[Seq[K]]
val listTemp2:Seq[Int] = listOfS.get.asInstanceOf[Seq[Int]]
println("ListTemp:")
println(listTemp(1)) //print S(i2,k2,s2)
println(listTemp(1).isInstanceOf[S])   // true
println(listTemp(1).isInstanceOf[K])   // false
println(listTemp2(1)) //print S(i2,k2,s2)
println(listTemp2(1).isInstanceOf[Int])   // false
println(listTemp2(1).isInstanceOf[S]) // won't compile