在 Scala 中提取后代的子列表

Extract sublist of descendants in Scala

我有一个 class Foo extends Bar 和一个 List 或其他基础集合 class:

val bars: Iterable[Bar] 

我需要从集合中提取所有 Foo 元素。以下是代码:

val fooes: Iterable[Foo] = bars
    .filter(x => Try(x.isInstanceOf[Foo]).isSuccess))
    .map(_.isInstanceOf[Foo])

有没有更简洁的方法?

val fooes: Iterable[Foo] = bars.collect{case foo:Foo => foo}

.collect() 方法将部分函数作为其参数。在这种情况下,该函数仅为 Foo 类型定义。所有其他的都被忽略。

总的来说值得记住的几个可能的重写

  • filter 后跟 map 作为 collect
  • isInstanceOf 后跟 asInstanceOf 作为与 typed pattern
  • 的模式匹配

因此出现以下 discouraged 样式

bars
  .filter { _.isInstanceOf[Foo] }
  .map    { _.asInstanceOf[Foo] }

可以重写为惯用风格

bars collect { case foo: Foo => foo }

...writing type tests and casts is rather verbose in Scala. That's intentional, because it is not encouraged practice. You are usually better off using a pattern match with a typed pattern. That's particularly true if you need to do both a type test and a type cast, because both operations are then rolled into a single pattern match.

请注意,打字图案的本质仍然只是 runtime type check followed by runtime type cast,也就是说,它仅代表更好的风格服装,而不是增加打字安全性。例如

scala -print -e 'lazy val result: String = (42: Any) match { case v: String => v }'

扩展为

<synthetic> val x1: Object = scala.Int.box(42);
if (x1.$isInstanceOf[String]()) {
  <synthetic> val x2: String = (x1.$asInstanceOf[String]());
  ...
}

我们清楚地看到类型检查 isInstanceOf 之后是类型转换 asInstanceOf.