在Try中,泛型类型的Scala AsInstance不会失败

在Try中,泛型类型的Scala AsInstance不会失败,scala,generics,casting,Scala,Generics,Casting,尝试将字符串强制转换为双精度显然会失败: scala> Try("abc".asInstanceOf[Double]) res11: scala.util.Try[Double] = Failure(java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double) 但是,如果我将上述定义为一个函数: scala> def convertAsTypeOf[T](anyValue: An

尝试将
字符串
强制转换为
双精度
显然会失败:

scala> Try("abc".asInstanceOf[Double])
res11: scala.util.Try[Double] = Failure(java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double)
但是,如果我将上述定义为一个函数:

scala> def convertAsTypeOf[T](anyValue: Any): Try[T] = Try(anyValue.asInstanceOf[T])
convertAsTypeOf: [T](anyValue: Any)scala.util.Try[T]
奇怪的是,当我尝试将
字符串
转换为
双精度时,它返回了成功:

scala> convertAsTypeOf[Double]("abc")
res10: scala.util.Try[Double] = Success(abc)
如果我试图从成功中获得价值,我会得到以下异常:

scala> convertAsTypeOf[Double]("abc").get
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double
        at scala.runtime.BoxesRunTime.unboxToDouble(BoxesRunTime.java:119)

为什么会发生这种情况?有没有办法解决这个问题,并在泛型函数中设置
为[T]
的实例?

由于类型擦除,运行时类型
T
是未知的,因此
asInstanceOf
实际上无法检查它所执行的强制转换。事实上,它编译为no-op。然而,当
.get
最终完成时,将转换为
Double
,并且因为这里已知类型,所以我们可以得到
类CastException

如果将
convertAsTypeOf
更改为使用
ClassTag

def convertAsTypeOf[T](anyValue: Any)(implicit tag: ClassTag[T]): Try[T] =
  Try(tag.runtimeClass.cast(anyValue).asInstanceOf[T])
然后,当您期望:

scala> convertAsTypeOf[Double]("abc")
res1: scala.util.Try[Double] = Failure(java.lang.ClassCastException: Cannot cast java.lang.String to double)

ClassTag
在运行时表示类型
T
,允许对照它检查值。

由于类型擦除,类型
T
在运行时是未知的,因此
asInstanceOf
实际上无法检查它执行的强制转换。事实上,它编译为no-op。然而,当
.get
最终完成时,将转换为
Double
,并且因为这里已知类型,所以我们可以得到
类CastException

如果将
convertAsTypeOf
更改为使用
ClassTag

def convertAsTypeOf[T](anyValue: Any)(implicit tag: ClassTag[T]): Try[T] =
  Try(tag.runtimeClass.cast(anyValue).asInstanceOf[T])
然后,当您期望:

scala> convertAsTypeOf[Double]("abc")
res1: scala.util.Try[Double] = Failure(java.lang.ClassCastException: Cannot cast java.lang.String to double)

ClassTag
表示运行时的类型
T
,允许对照该类型检查值。

发生这种情况的原因是类型擦除,这使得对泛型T的[T]的安装无效。我不知道为什么编译器没有发出任何警告

您可以使用类标记强制执行检查。大概是这样的:

import reflect.ClassTag

def convertAsTypeOf[T : ClassTag](anyValue: Any): Try[T] = Try {
    anyValue match { case t: T => t }
}

这是因为编译器将在大小写匹配中使用隐式ClassTag(如果它可用)(如果不可用则生成警告)。

发生这种情况的原因是类型擦除,这使得泛型T的[T]安装无效。我不知道为什么编译器没有发出任何警告

您可以使用类标记强制执行检查。大概是这样的:

import reflect.ClassTag

def convertAsTypeOf[T : ClassTag](anyValue: Any): Try[T] = Try {
    anyValue match { case t: T => t }
}

这是因为编译器将在大小写匹配中使用隐式类标记(如果它可用,则生成警告)。

asInstanceOf[T]
让您在知道编译器没有的东西时重新获得类型安全性。如果
T
被删除,类型安全性不需要在某个地方进行运行时检查吗?编译器如何决定将该检查放在何处?当您将该值用作某种类型时,就会发生这种情况。在REPL中,使用
:javap-prv-
比较
valx=identity(2.0)
valx:Any=identity(2.0)
。或者
f[A](A:A)=42。作为[A]
的安装,它将在第一种情况下抛出。
asInstanceOf[T]
让您在知道编译器不知道的事情时重新获得类型安全性。如果
T
被删除,类型安全性不需要在某个地方进行运行时检查吗?编译器如何决定将该检查放在何处?当您将该值用作某种类型时,就会发生这种情况。在REPL中,使用
:javap-prv-
比较
valx=identity(2.0)
valx:Any=identity(2.0)
。或者
f[A](A:A)=42。作为[A]
的替代,它将在第一种情况下抛出。有人应该提到
import shapeless.syntax.typeable;“abc”.cast[Double]
用于用例。有人应该提到
导入shapeless.syntax.typeable.\u;“abc”.cast[Double]
用于用例。您好,谢谢您的回答。它不适用于双精度或整型参数
scala>convertAsTypeOf[Double](32.2)res86:scala.util.Try[Double]=失败(java.lang.ClassCastException:无法将java.lang.Double转换为Double)
您好,谢谢您的回答。它不适用于双精度或整型参数
scala>convertAsTypeOf[Double](32.2)res86:scala.util.Try[Double]=失败(java.lang.ClassCastException:无法将java.lang.Double转换为Double)