给定包含变量类型项的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
。在case
语法中不允许参数化Scala类型。
是否有Scala-esque方法来参数化此过滤操作? (也许使用collect
函数之外的其他东西。)是否需要反射?
答案 0 :(得分:1)
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)
,依此类推。
答案 1 :(得分:1)
您不能将类型本身分配给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)
提取,或者您可以直接提供:{{1}}。