如何写asInstanceOfOpt [T]其中T&lt ;: Any

时间:2011-10-24 10:00:28

标签: scala

How to write "asInstanceOfOption" in Scala的答案中给出了asInstanceOfOpt的安全版asInstanceOf的方便实现。看来,Scala 2.9.1,这个解决方案现在只适用于AnyRef:

class WithAsInstanceOfOpt(obj: AnyRef) {
  def asInstanceOfOpt[B](implicit m: Manifest[B]): Option[B] =
    if (Manifest.singleType(obj) <:< m)
      Some(obj.asInstanceOf[B])
    else
      None
}

可以重写以支持Any吗?

3 个答案:

答案 0 :(得分:1)

如果查看Scala API,函数singleType将采用AnyRef类型的参数。我真的不知道这个决定的背景,但似乎你需要解决它。而不是使用方法singleType我建议使用classType方法,它基本上可以为任何类制作清单。它需要更多的代码,但它可能看起来像这样:

class WithAsInstanceOfOpt(obj : Any) {
  def asInstanceOfOpt[B : Manifest] : Option[B] =   // [B : Manifest] is shorthand for [B](implicit m : Manifest[B])
    if (Manifest.classType(manifest, obj.getClass) <:< manifest)
      Some(obj.asInstanceOf[B])
    else None
}

答案 1 :(得分:0)

这是2.9.x的工作代码。它将为2.10.x提供弃用警告,但使用ClassTag代替ManifestruntimeClass代替erasure将会修复它们。

//Precondition: classS must have been produced through primitiveToBoxed, because v will be boxed.
def ifInstanceOfBody[T, S](v: T, classS: Class[_]): Option[S] = {
  if (v == null || !classS.isInstance(v))
    None
  else
    Some(v.asInstanceOf[S])
}
object ClassUtil {
  import java.{lang => jl}

  private val primitiveToBoxedMap = Map[Class[_], Class[_]](
    classOf[Byte] -> classOf[jl.Byte],
    classOf[Short] -> classOf[jl.Short],
    classOf[Char] -> classOf[jl.Character],
    classOf[Int] -> classOf[jl.Integer],
    classOf[Long] -> classOf[jl.Long],
    classOf[Float] -> classOf[jl.Float],
    classOf[Double] -> classOf[jl.Double],
    classOf[Boolean] -> classOf[jl.Boolean],
    classOf[Unit] -> classOf[jl.Void]
  )
  def primitiveToBoxed(classS: Class[_]) =
    primitiveToBoxedMap.getOrElse(classS, classS)
}
class IfInstanceOfAble[T](v: T) {
  def asInstanceOfOpt[S](implicit cS: Manifest[S]): Option[S] =
    ifInstanceOfBody[T, S](v, ClassUtil.primitiveToBoxed(cS.erasure))
}
implicit def pimpInstanceOf[T](t: T) = new IfInstanceOfAble(t)

测试结果:

scala> 1.asInstanceOfOpt[Int]
res9: Option[Int] = Some(1)

scala> "".asInstanceOfOpt[String]
res10: Option[String] = Some()

scala> "foo".asInstanceOfOpt[String]
res11: Option[String] = Some(foo)

scala> 1.asInstanceOfOpt[String]
res12: Option[String] = None

scala> "".asInstanceOfOpt[Int]
res13: Option[Int] = None

代码比这里需要的更冗长,主要是因为我从我现有的代码库中获取它,我在其他地方重用ifInstanceOfBody。内联到asInstanceOfOpt会解决这个问题,并在某种程度上缩短代码,但大部分都是针对primitiveToBoxedMap的,并相信我找不到Scala标准库中提供的内容。

答案 2 :(得分:0)

您可以使用来自Miles Sabin的shapeless类型:

Type casting using type parameter

它处理原语和拳击:

scala> import shapeless._; import syntax.typeable._
import shapeless._
import syntax.typeable._

scala> 1.cast[Int]
res1: Option[Int] = Some(1)

scala> 1.cast[String]
res2: Option[String] = None

scala> "hello".cast[String]
res4: Option[String] = Some(hello)

scala> "foo".cast[Int]
res5: Option[Int] = None

您可以在此处查看来源,了解其编写方式:

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/typeable.scala