我有以下代码将值转换为默认类型:
def fct[T](value: Any, default: T): T = {
val result = value.asInstanceOf[T]
println(result, result.getClass.getName, result.isInstanceOf[T])
result
}
val res = fct("foo", 42)
Run Code Online (Sandbox Code Playgroud)
结果是:
(foo,java.lang.String,true)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(Test.sc2.tmp)
at #worksheet#.res$lzycompute(Test.sc2.tmp:7)
at #worksheet#.res(Test.sc2.tmp:7)
at #worksheet#.#worksheet#(Test.sc2.tmp:7)
Run Code Online (Sandbox Code Playgroud)
问题是:为什么要显示println?演员应该失败.我试图尝试/捕获3行,但在函数调用期间没有异常.
因为类型擦除,它不可能真正实现value.{as/is}InstanceOf[T]哪里T是一个类型参数.Scala的设计者认为它仍然应该编译,但value.asInstanceOf[T]实际上是一个无操作(就像(T) valueJava中的等价),而value.isInstanceOf[T]总是返回true(在Java中,value instanceOf T是编译器错误).(因为它永远不会做你想要的,我非常希望看到一个警告,至少是isInstanceOf.)
但是Scala允许使用你想做的事情ClassTag:
import scala.reflect.ClassTag
def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = {
val result = (tag match {
case ClassTag.Int => value.asInstanceOf[Int]
... same for other primitives
case _ => tag.runtimeClass.cast(value)
}).asInstanceOf[T]
println(result, result.getClass.getName, tag.runtimeClass.isInstance(result))
result
}
Run Code Online (Sandbox Code Playgroud)
(你仍然需要asInstanceOf[T]因为tag.runtimeClass 通常返回相同的类T代表但不总是,所以它的静态返回类型必须是Class[_]并cast返回Any).
但是,模式匹配: T处理ClassTag自动存在并且已经处理过拳击,所以
def fct[T](value: Any, default: T)(implicit tag: ClassTag[T]): T = value match {
case result: T => result
case _ => default // or whatever you want to do if value is not a T
}
Run Code Online (Sandbox Code Playgroud)
这是更好的方法.
| 归档时间: |
|
| 查看次数: |
869 次 |
| 最近记录: |