hi-*_*zir 5 scala type-inference pattern-matching scala-collections scala-compiler
让我们考虑以下特征:
sealed trait AB
case class A(a: Int) extends AB
case class B(b: Int) extends AB
Run Code Online (Sandbox Code Playgroud)
我试图将collect集合限制为特定的子类.
如果我尝试collect,匹配单个组件并重新组合元组:
scala> Seq.empty[(Int, AB)].collect { case (id, a @ A(_)) => (id, a) } : Seq[(Int, A)]
res6: Seq[(Int, ab.A)] = List()
Run Code Online (Sandbox Code Playgroud)
编译器很高兴,但如果尝试返回完整匹配:
scala> Seq.empty[(Int, AB)].collect { case x @ (_, A(_)) => x } : Seq[(Int, A)]
Run Code Online (Sandbox Code Playgroud)
事情变得丑陋:
<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)]
Run Code Online (Sandbox Code Playgroud)
为什么Scala编译器无法处理第二种情况?
这似乎是因为模式匹配以自上而下的方式进入子模式,而不将任何附加信息从子模式传递到根模式.
什么时候
x @ (_, A(_))
Run Code Online (Sandbox Code Playgroud)
匹配,都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).