Wie „asInstanceOf Option“ in Scala schreiben
-
05-07-2019 - |
Frage
Ist es möglich, eine „asInstanceOfOption“ Methode zu schreiben, das tun würde, was durch den folgenden (Schein-) Code bestimmt ist?
def asInstanceOfOption[T](o: Any): Option[T] =
if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None
Lösung
Bearbeiten Unter meiner ursprünglichen Antwort ist, aber Sie können dies erreichen jetzt mit
def asInstanceOfOption[T: ClassTag](o: Any): Option[T] =
Some(o) collect { case m: T => m}
Sie könnten Manifeste verwenden um die Tatsache zu bekommen, dass der Typ T
ist gelöschter bei der Kompilierung:
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]
Dann ist diese verwendet werden könnte:
scala> asInstanceOfOption[Int]("Hello")
res1: Option[Int] = None
scala> asInstanceOfOption[String]("World")
res2: Option[String] = Some(World)
Sie können sogar verwenden implizite Konvertierungen zu bekommen dies eine Methode zur Verfügung, auf Any
zu sein. Ich denke, ich ziehe die Methodennamen 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
}
}
Jetzt können Sie Code schreiben, wie:
"Hello".matchInstance[String] == Some("Hello") //true
"World".matchInstance[Int] == None //true
EDIT: aktualisierten Code für 2.9.x, wo man nicht Any
aber nur AnyRef
verwenden kann:
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
}
}
Andere Tipps
Hier ist eine Weiterentwicklung auf oxbow_lake aktualisierten Antwort, aktualisiert weiter erfordern 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
}
}
}
Dies kann dabei verwendet werden:
"Hello".asInstanceOfOpt[String] == Some("Hello") // true
"foo".asInstanceOfOpt[List[_]] == None // true
Doch wie in anderen Antworten erwähnt dies nicht funktioniert für Primitive wegen Boxen Probleme, noch nicht Generika handhaben, weil der Löschung. Um nicht zuzulassen Primitiven, beschränken ich obj
und T
AnyRef
zu verlängern. Für eine Lösung, die Primitiven behandelt, beziehen sich auf die Antwort für Matt R Followup Frage:
Wie schreibt asInstanceOfOpt [T], wobei T <: Alle
oder benutzen formlos 's typisierbarer, die Primitiven sowie viele Löschungsfälle behandelt:
Zum Zeitpunkt des Schreibens von oxbow_lakes Antwort (Ende '09), glaube ich scala.util.Try
war nicht verfügbar, aber jetzt (dh ab 2.10) Ich denke, scala.util.Try
ist die bevorzugte (oder auch zumindest besser aussehend) Art und Weise dies zu tun:
scala> Try((3).asInstanceOf[String]).toOption
res0: Option[String] = None
scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)