您需要提供 a ClassTag
,而不是 a TypeTag
,并使用模式匹配。 ClassTags
与模式匹配配合得很好。您甚至可以使用该collect
方法来执行filter
andmap
一起:
def filter[T, T2](data: Traversable[T2])(implicit ev: ClassTag[T]) = data collect {
case t: T => t
}
例如:
val data = Seq(new B, new B, new C, new B)
filter[B, A](data) //Traversable[B] with length 3
filter[C, A](data) //Traversable[C] with length 1
这样做的一个问题是,嵌套泛型类型可能无法按预期工作。
该collect
方法接受一个类型的参数PartialFunction
,表示不需要在整个域上定义的函数。当使用未定义的collect
元素时,将PartialFunction
被过滤掉,并相应地映射与某些case
语句匹配的元素。
您还可以使用存在类型并让编译器推断data
参数的类型以获得更简洁的语法。您还可以使用上下文边界:
def filter[T : ClassTag](data: Traversable[_]) = data collect { case t: T => t }
filter[B](data)
这里的方法的一个问题是您拥有的本机方法之间存在显着差异filter
:这些方法总是返回一段Traversable
时间,而本机filter
返回它可以返回的最佳类型。例如:
val data = Vector(new B, new B, new C, new B)
data filter { _.isInstanceOf[B] } //Vector[A]
data filter { _.isInstanceOf[B] } map { _.asInstanceOf[B] } //Vector[B]
data collect { case t: B => t } //Vector[B]. Note that if you know the type at the calling point, this is pretty concise and might not need a helper method at all
//As opposed to:
filter[B](data) //Traversable[B], not a Vector!
您可以通过CanBuildFrom
使用另一个隐式参数的模式来解决此问题。您还可以使用隐式类实质上将方法添加到类中(与上面显示的静态样式调用方法相反)。这一切加起来是一个非常复杂的方法,但如果您对这些增强功能感兴趣,我将把它留在这里:
implicit class RichTraversable[T2, Repr <: TraversableLike[T2, Repr], That](val trav: TraversableLike[T2, Repr]) extends AnyVal {
def withType[T : ClassTag](implicit bf: CanBuildFrom[Repr, T, That]) = trav.collect {
case t: T => t
}
}
这将允许您执行以下操作:
data.withType[B] //Vector[B], as desired