Scala asInstanceOf泛型类型在Try中没有失败

时间:2014-08-10 03:44:05

标签: scala generics casting

尝试将String投射到Double显然会失败:

scala> Try("abc".asInstanceOf[Double])
res11: scala.util.Try[Double] = Failure(java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double)

但是,如果我将上面定义为函数:

scala> def convertAsTypeOf[T](anyValue: Any): Try[T] = Try(anyValue.asInstanceOf[T])
convertAsTypeOf: [T](anyValue: Any)scala.util.Try[T]

奇怪的是,当我尝试将String转换为Double时,它会返回成功:

scala> convertAsTypeOf[Double]("abc")
res10: scala.util.Try[Double] = Success(abc)

如果我试图从Success中获取值,我会得到以下异常:

scala> convertAsTypeOf[Double]("abc").get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
        at scala.runtime.BoxesRunTime.unboxToDouble(BoxesRunTime.java:119)

为什么会这样?有没有办法解决这个问题,并在asInstanceOf[T]处于通用函数中时使用它?

2 个答案:

答案 0 :(得分:3)

由于类型擦除,类型T在运行时是未知的,因此asInstanceOf无法实际检查它所执行的转换。事实上,它编译为无操作。但是,当.get最终完成时,会对Double进行投射,并且因为此类型已知,我们可以获得ClassCastException

如果您更改convertAsTypeOf以使用ClassTag

def convertAsTypeOf[T](anyValue: Any)(implicit tag: ClassTag[T]): Try[T] =
  Try(tag.runtimeClass.cast(anyValue).asInstanceOf[T])

然后您会遇到错误:

scala> convertAsTypeOf[Double]("abc")
res1: scala.util.Try[Double] = Failure(java.lang.ClassCastException: Cannot cast java.lang.String to double)

ClassTag表示运行时的类型T,允许根据它检查值。

答案 1 :(得分:1)

这种情况发生的原因是类型擦除,这使得通用T的asInstanceOf [T]无用。我不知道编译器为什么不发出任何警告。

您可以使用ClassTag强制执行检查。像这样:

import reflect.ClassTag

def convertAsTypeOf[T : ClassTag](anyValue: Any): Try[T] = Try {
    anyValue match { case t: T => t }
}

这是有效的,因为如果可用,编译器将在大小写匹配中使用隐式ClassTag(如果不可用则生成警告)。