Pergunta

É possível escrever um método "asInstanceOfOption" que faria o que se pretende com o código a seguir (falso)?

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

Solução

Editar Abaixo está a minha resposta original, mas você pode fazer isso agora com

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

Você pode usar manifesta de contornar o fato de que o tipo T é Erased em tempo de compilação:

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]

Então isso poderia ser usado:

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

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

Você poderia até usar conversões implícitas para obter este é um método acessível em Any. Acho que eu prefiro o nome do 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
  }   
}

código Agora você pode escrever como:

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

EDIT: código atualizado para 2.9.x, onde não se pode usar Any mas apenas 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
  }   
}

Outras dicas

Aqui está uma elaboração sobre a resposta actualizado da oxbow_lake, mais atualizados para exigir 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
    }
  }
}

Isto pode ser usado fazendo:

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

No entanto, como mencionado em outras respostas isso não funcionar para primitivos por causa de problemas de boxe, nem lidar com os genéricos por causa de apagamento. Para primitivas Desautorizar, eu restrito obj e T para estender AnyRef. Para uma solução que lida com primitivas, consultar a resposta para a pergunta de acompanhamento de Matt R:

Como escrever asInstanceOfOpt [T], onde T <: Qualquer

Ou uso disforme 's tipável, que lida com primitivas, bem como muitos casos de apagamento:

conversão de tipos usando tipo de parâmetro

No momento da escrita da resposta de oxbow_lakes (final de '09), acredito scala.util.Try não estava disponível, no entanto, agora (ou seja, a partir de 2.10) Eu acho scala.util.Try é o (ou bem, pelo menos, mais bonito) forma preferida de fazer isso:

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

scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top