Как правильно использовать 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, но это не так. Это мое беспокойство.
- В третьем случае я получаю 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