Ответ 1
Описание
Исключение не выбрасывается здесь:
().asInstanceOf[T]
потому что это непроверенный листинг. JVM не может проверить, возможно ли сделать ()
в 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(())
}
}
Hackaround
В этом случае вы можете напрямую проверить 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