在Scala中提取后代子列表

问题描述 投票:1回答:2

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

val bars: Iterable[Bar] 

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

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

有简洁的方法吗?

scala casting scala-collections descendant
2个回答
7
投票
val fooes: Iterable[Foo] = bars.collect{case foo:Foo => foo}

.collect()方法采用部分功能作为其参数。在这种情况下,仅为Foo类型定义功能。其他所有内容都将被忽略。


2
投票

一般可能值得记住的重写之夫妇

  • [filter后跟mapcollect] >>
  • [isInstanceOf后跟asInstanceOf作为与typed pattern的模式匹配
  • 因此具有以下不鼓励的风格

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

可以重写为惯用风格

bars collect { case foo: Foo => foo }

请注意,键入样式的性质仍仅为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

© www.soinside.com 2019 - 2024. All rights reserved.