在尝试将值与复合类型进行模式匹配时,我偶然发现了一些神秘的(至少对我而言)编译器行为,我怀疑这可能是编译器错误。不过,在提交错误报告之前,如果比我更有知识的人可以看看这个并可能对正在发生的事情提供一些解释,我会很高兴。
我们从一些特征和案例类的层次结构开始:
sealed trait A
case class A1() extends A
case class A2() extends A
sealed trait B
我们想对复合类型的值进行操作:A with B
val a1: A with B = new A1() with B
val a2: A with B = new A2() with B
val as: Seq[A with B] = Seq(a1, a2)
首先,我尝试使用案例类提取器进行模式匹配:
Seq(a1, a2) foreach {
case A1() => println("a1")
case A2() => println("a2")
}
由于类型不匹配,上面的编译失败:
<console>:21: error: constructor cannot be instantiated to expected type;
found : A1
required: A with B
case A1() => println("a1")
^
<console>:22: error: constructor cannot be instantiated to expected type;
found : A2
required: A with B
case A2() => println("a2")
^
其次,我用实例类型匹配替换了提取器的使用:
as foreach {
case _: A1 => println("a1")
case _: A2 => println("a2")
}
以上确实编译并且确实有效,将“a1”和“a2”打印到屏幕上,但会发出关于无法访问代码的错误警告:
<console>:23: warning: unreachable code
case _: A2 => println("a2")
令人惊讶的是, make A
notsealed
消除了警告(尽管第一个模式匹配仍然无法编译)。
那么,问题来了:
- 第一个模式匹配应该编译吗?如果不是,那究竟为什么呢?
- 为第二个模式匹配发出的警告是完全错误的,还是我很幸运,并且在某些情况下这个匹配可能会出现错误的分支?
- 我应该提交错误报告还是我刚刚错过的一个长期已知的问题?
我已经在2.11.7
和上进行了测试2.11.8
。