首页 > 解决方案 > 为什么用模式匹配收集不能缩小特定的类?

问题描述

让我们考虑以下特征:

sealed trait AB
case class A(a: Int) extends AB
case class B(b: Int) extends AB

我试图将collect集合限制为特定的子类。

如果我尝试collect匹配单个组件并重新组装元组:

scala> Seq.empty[(Int, AB)].collect { case (id, a @ A(_))  => (id, a) } : Seq[(Int, A)]
res6: Seq[(Int, ab.A)] = List()

编译器很高兴,但如果尝试返回完全匹配:

scala> Seq.empty[(Int, AB)].collect { case x @ (_, A(_))  => x } : Seq[(Int, A)]

事情变得丑陋:

<console>:27: error: type mismatch;
 found   : Seq[(Int, ab.AB)]
 required: Seq[(Int, ab.A)]
       Seq.empty[(Int, AB)].collect { case x @ (_, A(_))  => x } : Seq[(Int, A)]

为什么 Scala 编译器无法处理第二种情况?

标签: scalapattern-matchingtype-inferencescala-collectionsscala-compiler

解决方案


这似乎是因为模式匹配以自上而下的方式进入子模式,而没有将任何附加信息从子模式传递到根模式。

什么时候

x @ (_, A(_))

匹配,所有x关于模式的知识是它具有预期的类型 (Int, AB),这成为推断的类型x

但是,当您将模式变量i和附加a到子模式时,可以提取更具体的信息并将其保存在 和 的推断类型ia。在这种特殊情况下a @ A(_)规范中的以下段落似乎相关:

模式绑定器x@p由模式变量x和模式组成p。变量的类型是模式x的静态类型。Tp

在 的情况下A(_),可以A仅通过查看模式的顶级元素来推断静态类型,而无需递归到子模式。因此,a推断出的类型是A,推断出的类型idInt,因此(id, a)推断出有类型(Int, A)


推荐阅读