我试图回答this问题,因为我认为我知道答案。 事实证明,我不太了解:/
这是我做过的测试:
class Inst[T] {
def is(x: Any) = scala.util.Try { as(x) }.isSuccess
def as(x: Any): T = x.asInstanceOf[T]
}
scala> new Inst[String].is(3)
res17: Boolean = true
scala> new Inst[String].as(3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
... 33 elided
这里发生了什么?为什么只有第二次调用as
抛出,而不是第一次调用?
答案 0 :(得分:10)
这是因为只有在对值执行某些操作时才抛出class-cast-exception,在强制转换后调用方法。例如,在REPL中,您将在第二种情况下进行toString
调用。注意:
new Inst[String].as(3); () // nothing happens
new Inst[String].as(3).toString; () // exception
这需要额外步骤的原因是Inst[T]
是通用的,类型参数T
在运行时被擦除;只有当调用站点(具有类型T
的静态知识)尝试在结果上调用方法时,才会进行实际的类型检查。
对于您的后续问题,toString
是在任何对象上定义的,因为T
是通用的,所以您有一个盒装整数(<: AnyRef
)和toString
以及{{ 1}}在println
方法中成功。因此is
失败的另一个例子是:
Try
答案 1 :(得分:2)
虽然@ 0 __的答案解释了为什么它不起作用,但这是如何使它工作:
class Inst[T](implicit tag: scala.reflect.ClassTag[T]) {
def is(x: Any) = tag.runtimeClass.isInstance(x)
// scala.util.Try { as(x) }.isSuccess will work as well
def as(x: Any): T = tag.runtimeClass.cast(x).asInstanceOf[T]
}
object Main extends App {
println(new Inst[String].is(3))
println(new Inst[String].as(3))
}
false
java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.String
at java.lang.Class.cast(Class.java:3369)
...