简体   繁体   中英

A way to avoid asInstanceOf in Scala

I have this hierarchy of traits and classes in Scala:

trait A
trait B[T] extends A {
  def v: T
}
case class C(v:Int) extends B[Int]
case class D(v:String) extends B[String]
val l:List[A] = C(1) :: D("a") :: Nil
l.foreach(t => println(t.asInstanceOf[B[_]].v))

I cannot change the type hierarchy or the type of the list.

Is there a better way to avoid the asInstanceOf[B[_]] statement?

您可以尝试模式匹配。

l.collect{case x :B[_] => println(x.v)}

You might try something like this:

for (x <- l.view; y <- Some(x).collect { case b: B[_] => b }) println(y.v)

It doesn't require any isInstanceOf or asInstanceOf , and never crashes, even if your list contains A s that aren't B[_] s. It also doesn't create any lengthy lists as intermediate results, only small short-lived Option s.


Not as concise, but also much less surprising solution:

for (x <- l) {
  x match {
    case b: B[_] => println(b.v)
    case _ => /* do nothing */
  }
}

If you could change the type of l to List[B[_]] , this would be the preferable solution.

I think the most ideomatic way to do it would be to supply B with an extractor object and pattern match for B values:

object B {
    def unapply[T](arg: B[T]): Some[T] =  Some(arg.v)
  }
l.collect{case B(x) => println(x)} 

If B is declared in a source file you can't alter you might need a different name for the extractor object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM