【问题标题】:Why are non case classes allowed to inherit sealed classes?为什么允许非案例类继承密封类?
【发布时间】:2021-07-19 05:45:10
【问题描述】:

我的印象是,密封类主要用于将所有详尽的子类编写在同一个编译单元(恰好是 Scala 中的一个文件)中。

但是,请考虑以下情况。我有一个名为 AnimalsPart1.scala 的文件,其中有以下声明:

sealed class Animal
case class Dog() extends Animal
case class Cat() extends Animal
class Herbivore() extends Animal

接下来,我有一个名为 AnimalPart2.scala 的文件,其中我有以下声明:

case class Hen() extends Herbivore
def whatAnimalAmI(a : Animal) = a match {
    case Dog() => "Dog"
    case Cat() => "Cat"
    case Hen() => "Hen"
}
println(whatAnimalAmI(new Hen()))

// prints "Hen" as the output

允许类继承密封类,然后让这些类在任何地方都可以继承,这破坏了密封类的创建原则。这是一个小例子,但如果上述属性成立,则很难列出给定密封类的详尽子类集。

因此,为什么允许非 case 类继承密封类?还有,我们如何处理上面的问题(Hen在声明了密封类的文件之外继承了一个Animal)?

【问题讨论】:

  • Hen 不是继承自 Animal,而是继承自 Herbivore,它不是密封的。密封只防止直接继承。

标签: scala inheritance case-class


【解决方案1】:

如果你想防止 class 被子类化,那么机制就是 final

sealed 类的意义在于classtrait 的所有直接 子类都在同一个文件中。这允许编译器通过查看所有直接子类是否匹配来判断 match 是否详尽。

问题中的match 没有捕获HerbivoreHerbivore 的其他子类,因此编译器知道它并不详尽(并且可能会给出警告)。

【讨论】:

    【解决方案2】:

    允许类继承密封类,然后让这些类在任何地方都可以继承,这破坏了密封类的创建原则

    原则是匹配直接子类型(以及类本身,如果它不是抽象的)是详尽的,在这种情况下

    def whatAnimalAmI(a : Animal) = a match {
        case Dog() => "Dog"
        case Cat() => "Cat"
        case h: Herbivore => "Herbivore"
    }
    

    这样您就不需要查看任何其他文件并发现Herbivore 有一些子类。所以这个原则没有被打破。

    现在,您确实也可以穷尽匹配,但即使 Herbivore 是一个案例类(或密封),您也可以通过省略它来做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      相关资源
      最近更新 更多