scala - 为什么用模式匹配收集不能缩小特定的类?
问题描述
让我们考虑以下特征:
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(_)
,规范中的以下段落似乎相关:
模式绑定器
x@p
由模式变量x
和模式组成p
。变量的类型是模式x
的静态类型。T
p
在 的情况下A(_)
,可以A
仅通过查看模式的顶级元素来推断静态类型,而无需递归到子模式。因此,a
推断出的类型是A
,推断出的类型id
是Int
,因此(id, a)
推断出有类型(Int, A)
。
推荐阅读
- django - Django:对查询集进行排序以具有特定的对象顺序
- class - Dart 类构造函数初始化构造函数主体中的字段
- amazon-web-services - 您可以从 HP-unix 系统挂载 AWS EFS 吗?
- typescript - TypeScript 在类中实现接口
- mysql - Ruby 续集多个运算符
- sql - pyodbc.ProgrammingError: ('42000'
- javascript - 如何禁用js字符串中的特殊换行符和其他字符
- linux - Systemd - 'Unit'部分中的未知左值'ConditionEnvironment'
- prolog - 如何在 Prolog 中定义和检查参数
- django - /messages/inbox/ 'account_tags' 处的 TemplateSyntaxError 不是已注册的标签库。必须是以下之一: