Можно ли написать метод asInstanceOfOption, который будет делать то, что предполагается следующим (фиктивным) кодом?
def asInstanceOfOption[T](o: Any): Option[T] =
if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None
Можно ли написать метод asInstanceOfOption, который будет делать то, что предполагается следующим (фиктивным) кодом?
def asInstanceOfOption[T](o: Any): Option[T] =
if (o.isInstanceOf[T]) Some(o.asInstanceOf[T]) else None
EDIT Ниже мой оригинальный ответ, но вы можете выполнить это сейчас с помощью
def asInstanceOfOption[T: ClassTag](o: Any): Option[T] =
Some(o) collect { case m: T => m}
Вы можете использовать манифесты, чтобы обойти тот факт, что тип T
стирается во время компиляции:
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]
Тогда это можно было бы использовать:
scala> asInstanceOfOption[Int]("Hello")
res1: Option[Int] = None
scala> asInstanceOfOption[String]("World")
res2: Option[String] = Some(World)
Вы даже можете использовать неявные преобразования, чтобы получить этот метод, доступный в Any
. Я думаю, что предпочитаю имя метода 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
}
}
Теперь вы можете написать код, например:
"Hello".matchInstance[String] == Some("Hello") //true
"World".matchInstance[Int] == None //true
EDIT: обновленный код для 2.9.x, где нельзя использовать Any
, но только 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
}
}
Здесь уточняется, что обновленный ответ oxbow_lake обновляется, требуя 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
}
}
}
Это можно использовать, выполнив:
"Hello".asInstanceOfOpt[String] == Some("Hello") // true
"foo".asInstanceOfOpt[List[_]] == None // true
Однако, как упоминалось в других ответах, это не работает на примитивы из-за проблем с боксом и не обрабатывает дженерики из-за стирания. Чтобы запретить примитивы, я ограничил obj
и T
расширением AnyRef
. Для решения, которое обрабатывает примитивы, обратитесь к ответу на вопрос Matt R:
Как написать asInstanceOfOpt [T], где T <: Any
Или используйте shapeless Typeable, который обрабатывает примитивы, а также многие случаи стирания:
Во время написания ответа oxbow_lakes (конец '09), я полагаю, что scala.util.Try
не был доступен, однако, теперь (т.е. с 2.10), я думаю, что scala.util.Try
является предпочтительным (или, по крайней мере, лучше ):
scala> Try((3).asInstanceOf[String]).toOption
res0: Option[String] = None
scala> Try("hello".asInstanceOf[String]).toOption
res1: Option[String] = Some(hello)