Scala将类型转换为变量类型

5

我有以下代码将 value 强制转换为类型 default:

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)

Which result is:

(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)

问题是:为什么println被显示了?强制转换应该会失败。我尝试使用try/catch处理这3行代码,但在函数调用期间没有引发任何异常。

1
很奇怪。请注意,我从你的代码中得到了 (Some(foo),scala.Some,true) 的结果。 - Yawar
抱歉,我会更正这个。 - Benjamin
我已经在2.10和2.11上进行了测试,问题依旧。 - Benjamin
1
@SarveshKumarSingh 不,这里没有懒惰的问题。 - Alexey Romanov
在Scala中,强制类型转换是一种代码异味。你需要进行什么样的操作才需要进行强制类型转换呢? - Kevin Meredith
显示剩余3条评论
1个回答

12
由于类型擦除的原因,无法实际实现value.{as/is}InstanceOf[T],其中T是一个类型参数。Scala的设计者决定仍然编译,但value.asInstanceOf[T]实际上是一个无操作(就像Java中等效的(T)value一样),而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
}

您仍然需要使用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
}

这是更好的方法。

3
这被称为启迪。 - sarveshseri
3
该短语可以翻译为“我长大后想成为你”。 - Yawar
无法编译:错误:(6,4)类型不匹配; 找到:result.type(具有基础类型Any) 需要:T 结果 - Benjamin
@Benjamin 抱歉,已修复。 - Alexey Romanov
1
@KevinMeredith “其中 T 是类型参数”。这里的 Int 不是类型参数。 - Alexey Romanov
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接