Scala类型过滤

时间:2015-02-16 00:45:36

标签: scala

我想制作一个按类型

过滤元素的算法

我做了类似的事

trait Valor
case class A() extends Valor
case class B() extends Valor
case class C() extends Valor

val list : List[Valor] = List(
  A(), A(),
  B(), B(), B(),
  C()
)
def getOfType[T](list: List[_]) = {
  list.filter {
    case _ : T => true
    case _ => false
  }
}
getOfType[A](list)

但它的输出是

  

列表[任意] =列表(A(),A(),B(),B(),B(),C())

我知道它根本不会编译。但为什么它会编译并给出如此奇怪的结果?

2 个答案:

答案 0 :(得分:4)

(如果您对可能的解决方案感兴趣;不适合评论)


首先,我们需要一些进口

import scala.reflect.ClassTag

然后我们可以告诉编译器在编译时为类型参数T生成ClassTag
使用此ClassTag,我们可以将所需的类与每个元素的类进行比较。

def getOfType[T](list: List[_])(implicit tag: ClassTag[T]): List[_] = {
  list.filter { elem => tag.runtimeClass.equals(elem.getClass) }
}

现在,我们可以更进一步,返回T的列表,而不是Any的列表

def getOfType[T](list: List[_])(implicit tag: ClassTag[T]): List[T] = {
  list.collect {
    case elem if tag.runtimeClass.equals(elem.getClass) => elem.asInstanceOf[T]
  }
}

有趣的是,神奇类型上的模式匹配在引入隐式ClassTag证据后起作用,这让我们可以简化很多事情

def getOfType[T : ClassTag](list: List[_]): List[T] = {
  list.collect {
    case elem : T => elem
  }
}

适用于这些简单的课程AB& C。但是,如果要过滤掉List[String]等多态类,则需要使用TypeTags。您可以查看演示多态类型过滤的example gist


我们可能会在函数中添加一个额外的显式Class[T]参数,我们可以用它来进行比较。

答案 1 :(得分:3)

这是因为删除后会消除: T(有警告),因为编译后通用方面会丢失,这意味着它无法在运行时检查泛型类型。所以基本上它根本就不做检查。该参数是任何事物的列表(List[_]),并且过滤器根本不会过滤,因此它会生成任何内容的列表。