2009-11-26 9 views
23

¿Es posible escribir un método "asInstanceOfOption" que haría lo que pretende el siguiente código (falso)?Cómo escribir "asInstanceOfOption" en Scala

def asInstanceOfOption[T](o: Any): Option[T] = 
    if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None 
+1

Esa es una expresión muy inteligente, y la respuesta de oxbow también fue muy inteligente. –

+0

@Daniel - ¡gracias por el elogio! –

Respuesta

25

EDITARcontinuación es mi respuesta original, pero se puede lograr esto ahora con

def asInstanceOfOption[T: ClassTag](o: Any): Option[T] = 
    Some(o) collect { case m: T => m} 

Se podría utilizar manifiestos de moverse por el hecho de que el tipo T es borran en tiempo de compilación:

scala> import scala.reflect._ 
import scala.reflect._ 

scala> def asInstanceOfOption[B](x : Any)(implicit m: Manifest[B]) : Option[B] = { 
    | if (Manifest.singleType(x) <:< m) 
    | Some(x.asInstanceOf[B]) 
    | else 
    | None 
    | } 
asInstanceOfOption: [B](x: Any)(implicit m: scala.reflect.Manifest[B])Option[B] 

entonces esto podría ser utilizado:

scala> asInstanceOfOption[Int]("Hello") 
res1: Option[Int] = None 

scala> asInstanceOfOption[String]("World") 
res2: Option[String] = Some(World) 

Incluso puede utilizar las conversiones implícitas para conseguir que esto sea un método disponible en Any. Creo que prefiero el nombre del método matchInstance:

implicit def any2optionable(x : Any) = new { //structural type 
    def matchInstance[B](implicit m: Manifest[B]) : Option[B] = { 
    if (Manifest.singleType(x) <:< m) 
     Some(x.asInstanceOf[B]) 
    else 
     None 
    } 
} 

Ahora puede escribir código como:

"Hello".matchInstance[String] == Some("Hello") //true 
"World".matchInstance[Int] == None    //true  

EDIT: código actualizado para 2.9.x, donde no se puede utilizar Any pero sólo AnyRef:

implicit def any2optionable(x : AnyRef) = new { //structural type 
    def matchInstance[B](implicit m: Manifest[B]) : Option[B] = { 
    if (Manifest.singleType(x) <:< m) 
     Some(x.asInstanceOf[B]) 
    else 
     None 
    } 
} 
+0

Gracias, eso es bastante ingenioso. –

+2

Solo una observación; el "tipo estructural" utiliza la reflexión para invocar el método 'matchInstance'.Si el rendimiento es más crítico, podría usar una conversión estándar a un tipo no estructural –

+1

El método 'matchInstance' no se invoca mediante reflejo, ya que _no_ es un tipo estructural sino simplemente una clase anónima. –

0

En el momento de la redacción de la respuesta de oxbow_lakes (finales del '09), creo scala.util.Try no estaba disponible, sin embargo, ahora (es decir, a partir del 2.10) Creo scala.util.Try es el preferido (o bien por lo menos más agradable de aspecto) forma de hacer esto:

scala> Try((3).asInstanceOf[String]).toOption 
res0: Option[String] = None 

scala> Try("hello".asInstanceOf[String]).toOption 
res1: Option[String] = Some(hello) 
+1

¿Por qué es preferible a 'Some (x) collect de oxbow_lake {case m: MyType => m}'? Intentaremos plantear una excepción y manejarla, lo que parece un poco excesivo ... –

+0

@Paul: si te refieres al rendimiento, entonces podrías tener razón; Simplemente creo que es más legible y más fácil de escribir también. –

+0

OK. La legibilidad siempre es personal, por supuesto, pero creo que la recopilación es clara (dice más directamente lo que se pretende) –

2

Aquí hay una elaboración sobre la respuesta actualizada de oxbow_lake, actualizado más a requerir Scala 2.10:

// Implicit value class 
implicit class Castable(val obj: AnyRef) extends AnyVal { 
    def asInstanceOfOpt[T <: AnyRef : ClassTag] = { 
    obj match { 
     case t: T => Some(t) 
     case _ => None 
    } 
    } 
} 

esto se puede utilizar haciendo:

"Hello".asInstanceOfOpt[String] == Some("Hello") // true 
"foo".asInstanceOfOpt[List[_]] == None // true 

sin embargo como se ha mencionado en otras respuestas esto no funciona para los primitivos debido a problemas de boxeo, ni manejar genéricos debido a la eliminación. Para rechazar las primitivas, restringí obj y T para ampliar AnyRef. Para una solución que maneja primitivas, remitirse a la respuesta a la pregunta de seguimiento de Matt R:

How to write asInstanceOfOpt[T] where T <: Any

O utilice shapeless 's tipable, que se ocupa de las primitivas, así como muchos casos de borrado:

Type casting using type parameter

Cuestiones relacionadas