如何在Scala中编写“asInstanceOf选项”

时间:2009-11-26 11:02:34

标签: scala

是否可以编写一个“asInstanceOfOption”方法来执行以下(伪造)代码的目的?

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

3 个答案:

答案 0 :(得分:28)

编辑 以下是我的原始答案,但您现在可以使用

完成此操作
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    

编辑: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
  }   
}

答案 1 :(得分:3)

这里有关于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

然而,正如其他答案中所提到的,由于拳击问题,这不适用于原语,也不会因擦除而处理泛型。为了禁止原语,我限制objT扩展AnyRef。对于处理原语的解决方案,请参阅Matt R的后续问题的答案:

How to write asInstanceOfOpt[T] where T <: Any

或者使用shapeless的Typeable,它处理原语以及许多擦除案例:

Type casting using type parameter

答案 2 :(得分:0)

在撰写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)