TL;博士
将此用于 Scala 2.9.x :
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.collect {
case t if m.erasure.isInstance(t) => t.asInstanceOf[T]
}
}
scala> typeOnly[String](List(1,2,"3",4))
res1: Seq[String] = List(3)
这适用于 Scala 2.10.x :
def typeOnly[T](seq : Seq[Any])(implicit tag : scala.reflect.ClassTag[T]) = {
seq.collect {
case t if tag.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}
正如Seq
定义为trait Seq[+A]
(键是+
),anySeq[S]
也是 a Seq[Any]
。
另一方面,正如已经说过的,T 在函数编译时被“遗忘”,所以你不能直接使用它。您必须以某种方式将 T 的类作为参数传递。
def typeOnly[T](seq : Seq[Any], c : Class[T]) : Seq[T] = {
seq.flatMap {
case t if c.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
在 Scala 中,除了Class[T]
之外,还有Manifest[T]
,它更强大一些,因此也更惯用。特别是,它有一个erasure
返回 a的方法Class[T]
。使用它,您可以像这样编写函数:
def typeOnly[T](seq : Seq[Any], m : Manifest[T]) : Seq[T] = {
seq.flatMap {
case t if m.erasure.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
似乎我们一无所获。但是,如果您很好地询问编译器(使用),它会在您调用函数时为您implicit
传递。Manifest
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.flatMap {
case t if m.erasure.isInstance(t) => Some(t.asInstanceOf[T])
case _ => None
}
}
例子:
scala> typeOnly[java.lang.Integer](List(1,2,"3",4))
res2: Seq[java.lang.Integer] = List(1, 2, 4)
scala> typeOnly[String](List(1,2,"3",4))
res3: Seq[String] = List(3)
scala> typeOnly[java.lang.Double](List(1,2,"3",4))
res4: Seq[java.lang.Double] = List()
还有更多的选择,其中一些更惯用。例如,您可以使用collect
部分定义的函数:
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) : Seq[T] = {
seq.collect {
case t if m.erasure.isInstance(t) => t.asInstanceOf[T]
}
}
警告:前面的示例适用于Scala 2.9.3及更低版本。如果您正在为Scala 2.10.x开发,Manifest#erasure
则已弃用。改用runtimeClass
:
def typeOnly[T](seq : Seq[Any])(implicit m : Manifest[T]) = {
seq.collect {
case t if m.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}
由于清单也将很快被弃用(请参阅下面的评论),您应该考虑使用 ClassTag。
def typeOnly[T](seq : Seq[Any])(implicit tag : scala.reflect.ClassTag[T]) = {
seq.collect {
case t if tag.runtimeClass.isInstance(t) => t.asInstanceOf[T]
}
}