scala 中是否有任何语言构造可以确保已处理所有模式匹配情况?

问题描述

假设我们有一个包含 3 个子案例类的特征。当我们将此特征与其中的两个匹配而忘记检查第三个时,我们可能在编译时没有注意到它,然后我们会收到运行时错误,尤其是在相互递归函数中使用此模式匹配的情况下。

是否有任何语言结构(可能是某种特定的模式匹配)可以确保处理所有子类?如果是这样,更复杂的模式匹配呢? (比仅仅匹配特征的子类更复杂) 有什么机制可以让我们确保这些模式匹配是完整的功能吗?

解决方法

这在一般情况下是不可能的。在具有动态代码加载的语言中,类层次分析相当于解决停机问题。因此,一般情况下编译器不可能知道特征有多少个子类。

您可以在运行时添加或删除子类,也可以向 trait 的子类添加或删除子类,等等。

但是,对于 sealed 特征,其子类也都至少为 sealedfinal(因此有效地“关闭" 在运行时加载新子类的能力)。在这种情况下,Scala 会将模式匹配优化为更有效的表示,并且您会收到非详尽模式匹配的警告。

现在您需要做的就是确保阅读警告,或告诉编译器将警告视为致命错误 (-Xfatal-warnings)。


[从技术上讲,JVM 不知道 sealed,因此您实际上仍然可以使用 Java 反射加载新的子类。然而,这意味着您将离开 Scala 的领域,而您是自己的:Scala 编译器无法保护您免受您在 Scala 之外所做的事情的影响。]

,

在此处回答:What is a sealed trait?

您需要使用密封特征并将编译器警告视为错误以确保匹配是详尽无遗的。

sealed trait Base
final class A extends Base
final class B extends Base

val data: Base = new B()

// you get compiler warning here that match might not be exhaustive
// add -Xfatal-warnings to fail compilation on warnings: 
// https://docs.scala-lang.org/overviews/compiler-options/index.html
data match { 
  case _: B => println("B")
}