Domanda

È possibile scrivere un " asInstanceOfOption " metodo che farebbe ciò che è inteso dal seguente codice (falso)?

def asInstanceOfOption[T](o: Any): Option[T] =
   if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None 
È stato utile?

Soluzione

MODIFICA Di seguito è la mia risposta originale, ma puoi farlo ora con

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

Puoi usare manifest per aggirare il fatto che il tipo T è cancellato al momento della compilazione:

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]

Quindi questo potrebbe essere usato:

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

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

Puoi persino usare conversioni implicite per rendere questo metodo disponibile su Any . Penso di preferire il nome del metodo 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
  }   
}

Ora puoi scrivere codice come:

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

EDIT: codice aggiornato per 2.9.x, dove non è possibile utilizzare Any ma 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
  }   
}

Altri suggerimenti

Ecco un'elaborazione sulla risposta aggiornata di oxbow_lake, ulteriormente aggiornata per richiedere 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
    }
  }
}

Questo può essere usato facendo:

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

Tuttavia, come menzionato in altre risposte, questo non funziona per i primitivi a causa di problemi di boxe, né gestisce i generici a causa della cancellazione. Per impedire le primitive, ho limitato obj e T per estendere AnyRef . Per una soluzione che gestisce i primitivi, fai riferimento alla risposta alla domanda di follow-up di Matt R:

Come scrivere comeInstanceOfOpt [T] dove T < ;: Any

Oppure usa Shapeless 's Typeable, che gestisce primitivi e molti casi di cancellazione:

Casting di tipo mediante il parametro type

Al momento della stesura della risposta di oxbow_lakes (fine '09), credo che scala.util. Try non fosse disponibile, tuttavia ora (cioè a partire da 2.10) penso scala.util. Try è il modo preferito (o almeno almeno più bello) per farlo:

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

scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top