编写一个通用的强制转换函数Scala

Bas*_*ter 17 generics scala

我试图实现编写一个方法,将Any的值转换为特定类型并返回选项而不是抛出像instanceOf这样的异常.Scala的行为与我的预期不符:

def cast[A](value: Any): Option[A] =
{
  try
  {
    Some(value.asInstanceOf[A])
  } catch
  {
    case e: Exception => None
  }
}
Run Code Online (Sandbox Code Playgroud)

考试:

val stringOption: Option[String] = cast[String](2)
stringOption must beNone
Run Code Online (Sandbox Code Playgroud)

失败并出现错误

java.lang.Exception: 'Some(2)' is not None
Run Code Online (Sandbox Code Playgroud)

有人知道为什么?

Rue*_*ler 21

在这里你的游行会擦掉雨水.因此,在运行时,类型A不再asInstanceOf[A]是已知的,并被编译为无操作.它只是让编译器认为结果值是A类型,但实际上并没有在运行时确保.

但是,您可以使用Scala的清单来解决它.不幸的是,JVM对原始类型/拳击的处理迫使我们做一些额外的工作.

以下工作,虽然它不处理类型的"弱一致性",这意味着例如Int不被视为Long,所以cast[Long](42)返回None.

def cast[A : Manifest](value: Any): Option[A] = {
  val erasure = manifest[A] match {
    case Manifest.Byte => classOf[java.lang.Byte]
    case Manifest.Short => classOf[java.lang.Short]
    case Manifest.Char => classOf[java.lang.Character]
    case Manifest.Long => classOf[java.lang.Long]
    case Manifest.Float => classOf[java.lang.Float]
    case Manifest.Double => classOf[java.lang.Double]
    case Manifest.Boolean => classOf[java.lang.Boolean]
    case Manifest.Int => classOf[java.lang.Integer]
    case m => m.erasure
  }
  if(erasure.isInstance(value)) Some(value.asInstanceOf[A]) else None
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*mes 5

这是因为类型擦除.在运行时,Ain Option[A]是未知的,因此您可以将a存储Some(3)在类型的变量中Option[String].

访问选项内的值时会发生异常:

scala> val result = cast[String](2)
result: Option[String] = Some(2)

scala> result.get
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        at .<init>(<console>:10)
        at .<clinit>(<console>)
        // ...
Run Code Online (Sandbox Code Playgroud)

  • "Option [A] .getOrElse [B]`的返回类型必须是"A"和"B"的超类型.在`String`和`Int`的情况下,返回类型是`Any`,你当然可以将`2`转换为`Any`.如果你试过`getOrElse("42")`你会得到一个`ClassCastException`,因为返回类型是`String`. (2认同)