可以说我有一个像这样的数组*:
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
似乎很有限,所以我想它与诸如类型擦除之类的丑陋事情有关。*
Any
和asInstanceOf
可以模仿第三方代码的行为,因此请不要再赘述。**在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
。