让我们考虑以下特征:
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编译器无法处理第二种情况?
最佳答案
似乎这是因为模式匹配以自上而下的方式进入了子模式,而没有将任何其他信息从子模式传递到根模式。
什么时候
x @ (_, A(_))
匹配时,
x
所知道的所有模式就是它具有预期的(Int, AB)
类型,这成为x
的推断类型。但是,当您将模式变量
i
和a
附加到子模式时,可以提取更多特定信息并将其保存在推断的i
和a
类型中。在a @ A(_)
的这种特殊情况下,the following paragraph in the spec似乎是相关的:A pattern binder
x@p
consists of a pattern variablex
and a patternp
. The type of the variablex
is the static typeT
of the patternp
.
在
A(_)
的情况下,仅查看模式的顶级元素即可将静态类型推断为A
,而无需递归到子模式。因此,推断a
的类型为A
,推断id
的类型为Int
,因此推断(id, a)
的类型为(Int, A)
。
关于scala - 为什么用模式匹配收集不能缩小特定类别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50551318/