Scala: who can explain this?

后端 未结 1 1144
渐次进展
渐次进展 2021-02-12 14:24

Consider the following Scala code:

case class Data[T](value: Option[T]) {
  def get: T = try {
    doGet
  } catch {
    case e: Exception => throw new Illega         


        
相关标签:
1条回答
  • 2021-02-12 15:05

    Explanation

    Exception isn't thrown here:

    ().asInstanceOf[T]
    

    because this is an unchecked cast - JVM cannot verify if it is possible to cast () into T, because it has no information about T due to type erasure.

    Instead, exception is thrown here

    Data[Integer](None).get
    

    because the result of get is cast into an Integer and that is something that JVM can verify. So, ClassCastException is actually thrown outside of get.

    BTW, javac always warns about unchecked casts, I don't know why scalac doesn't.

    Workaround

    To some extent, it is possible to work around type erasure here using ClassTag and reflection-based casting:

    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

    For this use case, you can inspect the ClassTag directly:

    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
    
    0 讨论(0)
提交回复
热议问题