Scala:isInstanceOf后跟asInstanceOf

Chr*_*jee 3 scala

在我的团队中,我经常看到队友写作

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)如果没有,上述两个选项中哪一个应该是首选?

Kol*_*mar 7

你可以使用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)