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

时间:2011-08-14 20:14:41

标签: generics scala

我正在尝试实现编写一个方法,将Any的值转换为特定类型并返回选项而不是抛出像instanceOf这样的异常。 Scala表现得不像我预期的那样:

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

测试:

val stringOption: Option[String] = cast[String](2)
stringOption must beNone

因错误

而失败
java.lang.Exception: 'Some(2)' is not None

有人知道为什么?

3 个答案:

答案 0 :(得分:21)

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

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

以下工作,虽然它不处理类型的“弱一致性”,这意味着例如Int不被视为长整数,因此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
}

答案 1 :(得分:5)

这是因为类型擦除。在运行时,A中的Option[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>)
        // ...

答案 2 :(得分:2)

我刚才做了几乎相同的事情,Scala 2.10,TypeTags(由于类型擦除)和来自scalaz的ValidationNEL:

import scala.reflect.runtime.universe._

def as[T: TypeTag](term: Any): ValidationNEL[String, T] =
  if (reflect.runtime.currentMirror.reflect(term).symbol.toType <:< typeOf[T])
    term.asInstanceOf[T].successNel[String]
  else
    ("Cast error: " + term + " to " + typeOf[T]).failNel[T]

使用Option而不是Validation,它看起来像这样:

  def as[T: TypeTag](term: Any): Option[T] =
  if (reflect.runtime.currentMirror.reflect(term).symbol.toType <:< typeOf[T])
    Some(term.asInstanceOf[T])
  else
    None

我在这里得到了我的信息:How to know if an object is an instance of a TypeTag's type?Runtime resolution of type arguments using scala 2.10 reflection