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

val foo: Any = 1 : Int
Option(foo.asInstanceOf[String])


由于明显的原因而失败:

// java.lang.ClassCastException: java.lang.Integer cannot be cast to
// java.lang.String
// ... 48 elided


接下来让我们考虑以下课程:

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


据我所知,getAs的行为应与之前apply后跟asInstanceOf的行为相同。

令人惊讶的是事实并非如此。单独调用时会引发异常:

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


但是用Option包裹成功时:

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

DummyRow().getAsOption[String]
// Option[String] = Some(1)


并且仅在我尝试访问包装的值时失败:

stringOption.get
// java.lang.ClassCastException: java.lang.Integer cannot be cast to
// java.lang.String
// ... 48 elided


那么这里发生了什么? ClassCastException似乎很有限,所以我想它与诸如类型擦除之类的丑陋事情有关。



* AnyasInstanceOf可以模仿第三方代码的行为,因此请不要再赘述。

**在Scala 2.10.5、2.11.7中测试

***如果您对上下文感兴趣,可以查看Using contains in scala - exception

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


Why does `.asInstanceOf` sometimes throw, and sometimes not?
Why asInstanceOf doesn't throw a ClassCastException?

最佳答案

以下是您问题的简化版本,并带有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])


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

10-06 11:27