按类型划分的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的可能性及其类型系统和集合库的困难的完美例子。我希望很快就能掌握这样的东西。