Scala的密封抽象类与抽象类的区别

75

sealed abstractabstract Scala类有什么区别?

2个回答

95

不同之处在于,密封类的所有子类(无论是否为抽象类)都必须与密封类位于同一文件中。


38
有些不太明显的事情(至少对我来说不是)是,封闭类的“子孙类”也可以在其他文件中: 假设有封闭类A;B继承A;C继承B。B必须与A在同一文件中,但C可以在同一个文件中或另一个文件中。 - Sandor Murakozi
8
如果你想达到这个目的,你也需要将B声明为一个sealed类。封闭只涉及直接继承。 - natbusa

80

回答所述,所有直接继承密封类(抽象或非抽象)的子类必须在同一个文件中。这样做的实际后果是编译器可以在模式匹配不完整时发出警告。例如:

sealed abstract class Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf[T](value: T) extends Tree
case object Empty extends Tree

def dps(t: Tree): Unit = t match {
  case Node(left, right) => dps(left); dps(right)
  case Leaf(x) => println("Leaf "+x)
  // case Empty => println("Empty") // Compiler warns here
}

如果Treesealed,那么编译器会发出警告,除非最后一行被取消注释。


1
为什么编译器在没有“sealed”关键字的情况下无法推断出模式匹配不完整? - sasha.sochka
7
假设我将其编译并将其放入一个jar文件中,没有使用sealed关键字。此时已经全部编译完成,包括match语句。现在,另一个用户获取此jar文件并扩展Tree。没有任何阻止他这样做的东西,但此时match语句不再完整。由于他不是在编译它,只是从你的jar文件中使用它,编译器无法向他发出警告。而且,由于你在创建jar文件时不知道这一点,因此编译器也不能为你提供警告。 - Daniel C. Sobral
@DanielCSobral,你写道“但是,在那个点上,匹配语句不再完整”。在编译您发布的原始代码(但没有sealed关键字)之前,此时匹配语句还不完整,难道不是吗?这似乎很容易推断,因为即使没有新孩子(编译器还不知道它们),也没有‘Empty’分支。我谈到的是为创建jar文件的人提供警告,而不是使用它的人。 - sasha.sochka
1
@sasha.sochka 嗯,我想它可以警告“Empty”丢失,但重点是,即使您添加了“Empty”,它仍然可能不完整或完整,这取决于单独编译时发生了什么。 - Daniel C. Sobral
是的,我同意你的看法。 - sasha.sochka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接