尝试将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]
处于通用函数中时使用它?
答案 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(如果不可用则生成警告)。