为什么使用Option包装泛型方法调用会延迟ClassCastException?

zer*_*323 16 generics scala classcastexception scala-option scala-generics

可以说我有一个像这样的数组*:

val foo: Any = 1 : Int
Option(foo.asInstanceOf[String])
Run Code Online (Sandbox Code Playgroud)

由于显而易见的原因失败:

// java.lang.ClassCastException: java.lang.Integer cannot be cast to 
// java.lang.String
// ... 48 elided
Run Code Online (Sandbox Code Playgroud)

接下来让我们考虑以下类:

case class DummyRow() {
  val foo: Any = 1 : Int
  def getAs[T] = foo.asInstanceOf[T]
  def getAsOption[T] = Option(foo.asInstanceOf[T])
}
Run Code Online (Sandbox Code Playgroud)

至于我可以告诉大家getAs应该的行为方式与以前一样apply,然后asInstanceOf.

令人惊讶的是事实并非如此.单独调用时会抛出异常:

DummyRow().getAs[String]
// java.lang.ClassCastException: java.lang.Integer cannot be cast to 
// java.lang.String
// ... 48 elided
Run Code Online (Sandbox Code Playgroud)

但当Option成功包装时:

val stringOption = Option(DummyRow().getAs[String])
// Option[String] = Some(1)

DummyRow().getAsOption[String]
// Option[String] = Some(1)
Run Code Online (Sandbox Code Playgroud)

并且只有在我尝试访问包装值时才会失败:

stringOption.get
// java.lang.ClassCastException: java.lang.Integer cannot be cast to 
// java.lang.String
// ... 48 elided
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?它似乎有限,ClassCastException所以我猜它与类型擦除等一些丑陋的东西有关.


*AnyasInstanceOf在那里模仿的第三方代码的行为,所以请让我们不要纠缠于这一点.

**在Scala 2.10.5,2.11.7中测试过

***如果您对上下文感兴趣,可以查看在scala使用包含 - 异常

****评论中链接的其他相关问题:

alm*_*dar 9

以下是您的问题的简化版本,附加案例 Any

def getAs[T] = (1:Int).asInstanceOf[T]

//blows up
getAs[String]

//blows up
def p(s:String): Unit = {}
p(getAs[String])

//works
def p[T](s:T): Unit = {}
p(getAs[String])

//works
def p(s:Any): Unit = {}
p(getAs[String])
Run Code Online (Sandbox Code Playgroud)

因为您使用泛型参数创建方法,所以运行时不需要"触摸"该值,因为它不关心.通用将被视为Any/ Object在运行时.