2011-10-24 16 views
9

Hay una implementación práctica de asInstanceOfOpt, una versión segura de asInstanceOf, dada en la respuesta a How to write "asInstanceOfOption" in Scala. Parece ser que, Scala 2.9.1, esta solución ahora sólo funciona con AnyRef:Cómo escribir comoInstanceOfOpt [T] donde T <: Any

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

puede esto ser reescrito para soportar cualquier?

Respuesta

1

Si mira en la API de Scala, la función singleType toma un parámetro de tipo AnyRef. Realmente no conozco los antecedentes de esta decisión, pero parece que necesitas evitarla. En lugar de usar el método singleType, sugeriría usar el método classType que básicamente puede hacer un manifiesto para cualquier clase. Que va a tomar un poco más de código, pero podría ser algo como esto:

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 
} 
+0

El código anterior no funciona debido al boxeo. '1.asInstanceOfOpt [Int]' devuelve 'None', mientras que' 1.asInstanceOfOpt [java.lang.Integer] 'devuelve' Some (1) 'con el tipo' Option [Integer] '. Uno necesita mapear los tipos manualmente (voy a publicar una solución). – Blaisorblade

0

Aquí está el código de trabajo para 2.9.x. Proporcionará advertencias de depreciación para 2.10.x, pero usando ClassTag en lugar de Manifest y en lugar de erasure, los reparará.

resultados de las pruebas
//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 

El código es un poco más detallado de lo necesario aquí, sobre todo porque la tomé de una base de código existente de la mina donde reutilizar ifInstanceOfBody en otro lugar. Incluir en asInstanceOfOpt lo arreglaría y acortaría un poco el código, pero la mayoría es para primitiveToBoxedMap, y créame que no pude encontrar algo así en la biblioteca estándar de Scala.

0

Usted podría utilizar shapeless 's tipable de Miles Sabin:

Type casting using type parameter

Maneja primitivas y el boxeo:

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 

Se puede ver la fuente aquí para ver cómo está escrito:

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

Cuestiones relacionadas