Here's working code for 2.9.x. It will give deprecation warnings for 2.10.x, but using ClassTag
instead of Manifest
and runtimeClass
instead of erasure
will fix them.
//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)
Testing results:
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
The code is slightly more verbose than needed here, mostly because I took it from an existing codebase of mine where I reuse ifInstanceOfBody elsewhere. Inlining into asInstanceOfOpt
would fix that and shorten the code somewhat, but most of it is for primitiveToBoxedMap
, and trust me that I could not find something like that available in the Scala standard library.