在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吗?
答案 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
代替Manifest
和runtimeClass
代替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