考虑以下 Scala 代码:
case class Data[T](value: Option[T]) {
def get: T = try {
doGet
} catch {
case e: Exception => throw new IllegalArgumentException
}
def doGet: T = value match {
case Some(v) => v
case None => ().asInstanceOf[T]
}
}
Data[Unit](None).get
Data[Integer](None).get // which exception is thrown here?
[剧透] 这是一个ClassCastException
;谁能解释为什么它没有被捕获并被替换IllegalArgumentException
?
PS:为了避免任何关于我为什么要这样做的问题:这是一些代码的简化版本,它使用 json4s 将某些字符串解析为Option[T]
;如果解析失败None
返回,如果T
was Unit
如果不行的话T
是其他类型。
解释
这里不会抛出异常:
().asInstanceOf[T]
因为这是未经检查的强制转换 - JVM 无法验证是否可以强制转换()
into T
,因为它没有关于T
由于类型擦除。
相反,这里抛出异常
Data[Integer](None).get
因为结果get
被铸成Integer
这是 JVM 可以验证的。所以,ClassCastException
实际上被扔到了外面get
.
BTW, javac
总是警告未经检查的强制转换,我不知道为什么scalac
没有。
解决方法
在某种程度上,可以使用以下方法来解决这里的类型擦除问题ClassTag
和基于反射的铸造:
import scala.reflect.{ClassTag, classTag}
case class Data[T: ClassTag](value: Option[T]) {
def get: T = try {
doGet
} catch {
case e: Exception => throw new IllegalArgumentException
}
def doGet: T = value match {
case Some(v) => v
case None => classTag[T].runtimeClass.asInstanceOf[Class[T]].cast(())
}
}
破解方法
对于此用例,您可以检查ClassTag
直接地:
scala> case class Data[T](value: Option[T])(implicit t: ClassTag[T]) {
| def get: T = value getOrElse (t match {
| case ClassTag.Unit => ().asInstanceOf[T]
| case _ => throw new IllegalArgumentException
| })
| }
defined class Data
scala> Data[Unit](None)
res6: Data[Unit] = Data(None)
scala> .get
scala> Data[Int](None).get
java.lang.IllegalArgumentException
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)