如何按类型参数化过滤Scala对象集合



给定一个包含变量类型项的Scala集合,我可以按类型进行过滤。

trait X
case class Y(y:Int) extends X
case class Z(z:Int) extends X
val l = List(Y(1), Y(2), Z(3), Z(4))
l.collect{case e: Y=>e} // returns List[Y] = List(Y(1), Y(2))
l.collect{case e: Z=>e} // returns List[Z] = List(Z(3), Z(4))

我需要参数化过滤。

val f = Y
l.collect{case e: f=>e} // should return List[Y] = List(Y(1), Y(2))

最后一行返回error: not found: type f。Scala类型的参数化在case语法中是不允许的。

是否有scala式的方法来参数化这个过滤操作?(可能使用collect功能以外的其他功能。)需要反射吗?

val f = Y中,Y不是类型,而是伴随对象。

你可以使用这样的类型:

type T = Y
l.collect{case e: T=>e} // returns List[Y] = List(Y(1), Y(2))

或者您可以使用伴侣对象,但只能用于某些参数计数:

val t = Y
l.collect{case e @ t(_)=>e} // returns List[Y] = List(Y(1), Y(2))

在这种情况下,你应该用e @ t(_, _)代替case class Y(y1:Int, y2:Int), e @ t(_, _, _)代替case class Y(y1:Int, y2:Int, y3:Int),等等。

不能将类型本身赋值给val,但可以使用方法类型参数进行参数化:

def filterOnType[T : ClassTag](c: Traversable[Any]): Traversable[T] = {
  val tag = implicitly[ClassTag[T]];
  c.collect { case tag(t) => t } 
}

ClassTag用于在运行时保存T的类信息。否则T将被擦除,.collect { case t: T => t }将与.collect { case t: AnyRef => t }相同。

scala> filterOnType[Y](l)
res7: Traversable[Y] = List(Y(1), Y(2))
scala> filterOnType[Z](l)
res8: Traversable[Z] = List(Z(3), Z(4))

如果你绝对需要在val中保留一些类型的表示,那么在这里保留ClassTag就可以了。val必须是隐式的才能被filterOnlyType拾取,或者您可以直接给出它:filterOnlyType[X](l)(myClassTagForX) .

最新更新