scala - 为什么用模式匹配收集不能缩小特定类别?

标签 scala pattern-matching type-inference scala-collections scala-compiler

让我们考虑以下特征:

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的推断类型。

但是,当您将模式变量ia附加到子模式时,可以提取更多特定信息并将其保存在推断的ia类型中。在a @ A(_)的这种特殊情况下,the following paragraph in the spec似乎是相关的:

A pattern binder x@p consists of a pattern variable x and a pattern p. The type of the variable x is the static type T of the pattern p.



A(_)的情况下,仅查看模式的顶级元素即可将静态类型推断为A,而无需递归到子模式。因此,推断a的类型为A,推断id的类型为Int,因此推断(id, a)的类型为(Int, A)

关于scala - 为什么用模式匹配收集不能缩小特定类别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50551318/

相关文章:

generics - ToString() 与字符串运算符的类型推断

scala - self 类型和特质子类有什么区别?

scala - 如何将 Spark Dataframe 列转换为字符串数组的单列

Java 有界泛型 : Type inference bug?(方法调用,JLS 15.12.2.7)

linux - 我如何 grep 使用 STDIN 作为查询模式,并使用文件作为主题?

rust - 针对元组的模式匹配

types - 为什么 Rust 不能推断 Iterator::sum 的结果类型?

Scala 和 UnionType 绑定(bind)到泛型类型

scala - Scala 中密封特征的迭代?

带有或匹配的 Scala 保护模式