scala - collect 方法何时以及为什么无法按子类型过滤 Scala 集合?
问题描述
与按类型过滤 Scala 列表相关,我正在尝试按值的类型过滤 Map,但我发现使用该collect
方法的解决方案会产生类型错误。
例如,考虑
abstract class A
class B extends A
class C extends A
val collection: Map[String, A] = Map(("One", new B), ("Two", new B),
("Three", new C), ("Four", new C))
val filtered: Map[String, B] = collection.collect {
case x@(_: String, _: B) => x }
这会产生一个编译错误,说明在需要Map[String, A]
时找到Map[String, B]
。PartialFunction 参数的重点不是collect
仅在某些值上定义吗?
但是,此方法适用于列表(如链接的帖子中所示):
val collection: List[A] = List(new B, new B, new C, new C)
val filtered: List[B] = collection.collect { case x: B => x }
但是,经过进一步的实验,我发现它也不适用于 Lists of Lists。这会产生C
无法转换为的运行时错误B
:
val collection: List[List[A]] = List(List(new B), List(new B),
List(new C), List(new C))
val filtered: List[List[B]] = collection.collect { case x: List[B] => x }
这里发生了什么?我错过了很多事情吗?
作为旁注,给出的解决方案之一确实有效:
val collection: Map[String, A] = Map(("One", new B), ("Two", new B),
("Three", new C), ("Four", new C))
val filtered = collection.flatMap {
case x@(_: String, _: B) => Some(x)
case _ => None
}
解决方案
问题是这x
是一个类型的变量(String, A)
。@
返回成功的元素unapply
,也就是地图的原始元素(String, A)
。
解决它的一种方法是使用从模式匹配中提取的值创建一个新元组(因为根据定义它们是 String 和 B)。
val collection: Map[String, A] = Map(("One", new B), ("Two", new B), ("Three", new C), ("Four", new C))
val filtered:Map[String, B] = collection.collect {
case (k: String, v: B) => (k, v)
}
filtered.foreach(println)
推荐阅读
- javascript - 本地存储/复选框/不显示值
- angular - 单击表格单元格时,更改为选择框
- javascript - Phaser 3 循环依赖问题
- typescript - `as const` 替代缩小数组文字元组,以避免 `readonly` 修饰符
- rust - 没有代码重复的单个测试中的多次恐慌
- php - 嵌套的 foreach 循环不拆分 Laravel 中的集合数据
- jquery - Jquery if/elseif 来回后没有隐藏
- mongodb - Mongodb和elasticsearch中的电子商务产品列表、过滤和搜索
- javascript - 带有 TypeScript/React/Material-UI 的全局主题
- c - 出现错误 -1073741819 (0xC0000005) - 在特定数字后使用矩阵