通用特征上的Scala模式匹配

时间:2016-10-25 13:24:07

标签: scala

我有一个如下定义的特征:

sealed trait MyTrait[+A] {
  def name: String
  def id: Long
  def someType: A 
}

我现在有一些案例类可以扩展这个特性,如下所示:

object MyTrait {
  case class One[+A](name: String, id: Long, someField: String, someType: A) extends MyTrait[A]

  case class Two[+A](name: String, id: Long, someField: String, someType: A) extends MyTrait[A]

  case class Three[+A](name: String, id: Long, someType: A) extends MyTrait[A]
}

现在,我有一个可能包含其中一个案例类的List,我必须从给定的List中收集各个案例类,并使用如下的instanceOf检查:

val myBigList = List(One[SomeType], Two[SomeType], Three[SomeType], One[SomeType])

val allOnes = myBigList.collect {
  case elem if elem.isInstanceOf[One[_]] => elem.asInstanceOf[One]]
}

val allTwos = myBigList.collect {
  case elem if elem.isInstanceOf[Two[_]] => elem.asInstanceOf[Two]]
}

val allThrees = myBigList.collect {
  case elem if elem.isInstanceOf[Three[_]] => elem.asInstanceOf[Three]]
}

有更好的方法吗?我的意思是有办法避免使用isInstanceOf和asInstanceOf吗?

1 个答案:

答案 0 :(得分:3)

如果您想将One[String]One[Int]放入一个存储桶中,这意味着如果您不关心内部类型,那就很好。

但是你可以使用foldLeft一次通过而不是三次通过。

def bucketize(list: List[MyTrait[_]]): (List[One[_]], List[Two[_]], List[Three[_]]) = {
  list.foldLeft(((List.empty[One[_]], List.empty[Two[_]], List.empty[Three[_]]))){ (r, c) => 
    val ((one, two, three)) = r
    c match { 
      case x: One[_] => ((one ++ List(x), two, three))
      case x: Two[_] => ((one, two ++ List(x), three))
      case x: Three[_] => ((one, two, three ++ List(x)))
    }
   }
}

你得到三个列表,第一个列表是List [One],第二个是List [Two]等等......

用法:

val ((one, two, three))  = bucketize(list)