按类型划分的scala过滤器

按类型划分的scala过滤器,scala,generics,runtime-type,Scala,Generics,Runtime Type,我读过TypeTag相关文章,但无法实现按元素类型过滤集合 例如: trait A class B extends A class C extends A val v = Vector(new B,new C) v filter ( _.isInstanceOf[B] ) 上面的代码运行良好。 但是,我想从v中提取过滤器。例如 def filter[T,T2](data:Traversable[T2]) = (data filter ( _.isInstanceOf[T])).asInst

我读过
TypeTag
相关文章,但无法实现按元素类型过滤集合

例如:

trait A
class B extends A
class C extends A

val v = Vector(new B,new C)
v filter ( _.isInstanceOf[B] )
上面的代码运行良好。 但是,我想从
v
中提取
过滤器
。例如

def filter[T,T2](data:Traversable[T2]) = (data filter (  _.isInstanceOf[T])).asInstanceOf[Traversable[T]]

//Then filter v by
filter[B,A](v)
在这种情况下,我得到警告
抽象类型T被取消选中,因为它是通过擦除消除的
。我试图使用
TypeTag
,但在运行时获取
Type
似乎并不容易

是否有任何优雅的解决方案来实现功能
过滤器

通过scala宏的任何解决方案都是可以接受的。

肯定有更简单的方法。下面的方法可行,但我希望有一个更简单的解决方案

trait A
case class B()
case class C()
import scala.reflect.runtime.universe._
import scala.util.Try
val m = runtimeMirror(getClass.getClassLoader)
def filter[T](data:Traversable[_])(implicit t:TypeTag[T]) = data collect {
      case i if Try(i.getClass.asSubclass(m.runtimeClass(typeOf[T].typeSymbol.asClass))).isSuccess => i.asInstanceOf[T]
    }
val v= Vector(new B,new C)

scala>     println(filter[B](v))
Vector(B()) //This gets printed

您需要提供一个
ClassTag
,而不是
TypeTag
,并使用模式匹配<代码>类标记可以很好地进行模式匹配。您甚至可以使用
collect
方法一起执行
filter
map

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
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!
这样做的一个问题是,对于嵌套泛型类型,它可能无法按预期工作

collect
方法接受类型为
PartialFunction
的参数,表示不需要在整个域上定义的函数。使用
collect
时,未定义
PartialFunction
的元素将被过滤掉,并且匹配某些
case
语句的元素将相应地映射

您还可以使用并让编译器推断
数据
参数的类型,以获得更简洁的语法。您还可以使用:

这里的方法的一个问题是,您拥有的本机
过滤器
方法之间存在显著差异:这些方法总是返回一个
可遍历的
,而本机
过滤器
返回它所能返回的最佳类型。例如:

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
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!
您可以通过使用另一个隐式参数使用模式来修复此问题。您还可以使用将方法添加到类中(与上面所示的静态样式调用方法相反)。所有这些加起来都是一个相当复杂的方法,但如果您对这些增强感兴趣,我将把它留在这里:

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
    }
}

嗨@BenReich,谢谢你的回答。你能解释一下
数据收集{case t:B=>t}
的语法吗?为什么不需要提供详尽的模式匹配?@worldterminator我添加了一个小编辑,解释了
collect
多一点。@BenReich谢谢,最后一段代码正是我需要的。这也是Scala的可能性及其类型系统和集合库的困难的完美例子。我希望很快就能掌握这样的东西。