Pregunta

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

def asInstanceOfOption[T](o: Any): Option[T] =
   if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None 
¿Fue útil?

Solución

EDITAR A continuación, se encuentra mi respuesta original, pero puedes lograrlo ahora con

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

Puede usar manifiestos para evitar el hecho de que el tipo T se borra en el momento de la 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 usado:

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

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

Incluso podría usar conversiones implícitas para que este sea un método disponible en Cualquiera . 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 puedes escribir código como:

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

EDITAR: código actualizado para 2.9.x, donde no se puede usar Any sino solo 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
  }   
}

Otros consejos

Aquí hay una explicación de la respuesta actualizada de oxbow_lake, que se actualizará aún más para 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 mencionó en otras respuestas, esto no funciona para los primitivos debido a problemas de boxeo, ni maneja los genéricos debido al borrado. Para no permitir primitivas, restringí obj y T para extender AnyRef . Para obtener una solución que maneje primitivas, consulte la respuesta a la pregunta de seguimiento de Matt R:

Cómo escribir comoInstanceOfOpt [T] where T < ;: Cualquier

O use el título de shapeless , que maneja primitivas y muchos casos de borrado:

Conversión de tipo usando el parámetro de tipo

Al momento de escribir la respuesta de oxbow_lakes (finales de '09), creo que scala.util.Try no estaba disponible, sin embargo, ahora (es decir, a partir de 2.10) creo que scala.util.Try es la forma preferida (o, al menos, de mejor apariencia) de hacer esto:

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

scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top