在我的团队中,我经常看到队友写作
list.filter(_.isInstanceOf[T]).map(_.asInstanceOf[T])
Run Code Online (Sandbox Code Playgroud)
但这对我来说似乎有点多余.
如果我们知道过滤列表中的所有内容都是一个实例,T那么为什么我们必须明确地这样做呢?
我知道一种替代方案,即使用match.
例如:
list.match {
case thing: T => Some(thing)
case _ => None
}
Run Code Online (Sandbox Code Playgroud)
但这有一个缺点,那就是我们必须明确说明一般情况.
所以,鉴于以上所述,我有两个问题:
1)还有另一种(更好吗?)方式做同样的事情?
2)如果没有,上述两个选项中哪一个应该是首选?
你可以使用collect:
list collect {
case el: T => el
}
Run Code Online (Sandbox Code Playgroud)
真正的类型只是工作(当然禁止类型擦除):
scala> List(10, "foo", true) collect { case el: Int => el }
res5: List[Int] = List(10)
Run Code Online (Sandbox Code Playgroud)
但是,正如@YuvalItzchakov所提到的,如果要匹配抽象类型T,则必须具有隐含ClassTag[T]的范围.
所以实现它的功能可能如下所示:
import scala.reflect.ClassTag
def filter[T: ClassTag](list: List[Any]): List[T] = list collect {
case el: T => el
}
Run Code Online (Sandbox Code Playgroud)
并使用它:
scala> filter[Int](List(1, "foo", true))
res6: List[Int] = List(1)
scala> filter[String](List(1, "foo", true))
res7: List[String] = List(foo)
Run Code Online (Sandbox Code Playgroud)
collect需要a PartialFunction,所以你不应该提供通用案例.
但如果需要,您可以将函数转换A => Option[B]为PartialFunction[A, B]with Function.unlift.这是一个例子,也shapeless.Typeable用于解决类型擦除:
import shapeless.Typeable
import shapeless.syntax.typeable._
def filter[T: Typeable](list: List[Any]): List[T] =
list collect Function.unlift(_.cast[T])
Run Code Online (Sandbox Code Playgroud)
使用:
scala> filter[Option[Int]](List(Some(10), Some("foo"), true))
res9: List[Option[Int]] = List(Some(10))
Run Code Online (Sandbox Code Playgroud)