Question

Est-il possible d’écrire un "asInstanceOfOption"? méthode qui ferait ce qui est prévu par le code (faux) suivant?

def asInstanceOfOption[T](o: Any): Option[T] =
   if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None 
Était-ce utile?

La solution

MODIFIER Voici ma réponse initiale, mais vous pouvez le faire maintenant avec

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

Vous pouvez utiliser des manifestes pour contourner le fait que le type T est effacé lors de la compilation:

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]

Ceci pourrait alors être utilisé:

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

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

Vous pouvez même utiliser des conversions implicites pour que cette méthode soit disponible sur Any . Je pense que je préfère le nom de la méthode 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
  }   
}

Vous pouvez maintenant écrire du code tel que:

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

EDIT: code mis à jour pour 2.9.x, dans lequel on ne peut pas utiliser Any mais seulement 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
  }   
}

Autres conseils

Voici une élaboration de la réponse mise à jour d'oxbow_lake, mise à jour ultérieurement pour nécessiter 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
    }
  }
}

Ceci peut être utilisé en faisant:

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

Toutefois, comme indiqué dans d'autres réponses, cela ne fonctionne pas pour les primitives en raison de problèmes de boxe, ni pour les génériques en raison de l'effacement. Pour interdire les primitives, j'ai limité obj et T à l'extension de AnyRef . Pour une solution prenant en charge les primitives, reportez-vous à la réponse de Matt R à la question suivante:

Comment écrire asInstanceOfOpt [T] où T < ;: Any

Ou utilisez le Typeless de Typeable, qui gère les primitives ainsi que de nombreux cas d'effacement:

Transtypage de caractères à l'aide du paramètre type

Au moment de la rédaction de la réponse d'oxbow_lakes (fin 2009), je crois que scala.util.Try n'était pas disponible, cependant (à compter de la version 2.10), je pense . scala.util.Try est le moyen préféré (ou du moins plus joli) de le faire:

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

scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top