《Scala编程》中有关于密封类的描述,但并没有提到密封特质。 在哪里可以找到更多关于密封特质的信息?
我想知道,密封特质和密封类是否相同? 如果不同,它们之间有什么区别? 何时使用密封特质是一个好主意(何时不是)?
sealed
特质只能在声明它的同一个文件中被扩展。
它们通常用于提供对enums
的替代方案。由于它们只能在单个文件中进行扩展,编译器可以知道所有可能的子类型并进行推理。
例如,使用以下声明:
sealed trait Answer
case object Yes extends Answer
case object No extends Answer
编译器会在匹配不全时发出警告:scala> val x: Answer = Yes
x: Answer = Yes
scala> x match {
| case No => println("No")
| }
<console>:12: warning: match is not exhaustive!
missing combination Yes
如果可能的子类型数量是有限且预先已知的,那么应该使用sealed traits(或sealed abstract class)。更多示例请参见列表和选项实现。
sealed abstract class Tree[T : Ordering]
sealed trait Tree[T : Ordering]
由于上下文限定(和视图限定)是使用隐式参数实现的。鉴于特质不能接收参数,因此你无法这样做。
个人而言,我更喜欢使用sealed trait
,除非某些特殊原因让我使用sealed abstract class
。我不是在谈论微妙的原因,而是一些明显的原因,你无法忽略,例如使用类型类。
[A:F]
)的工作方式与方差约束不同。相反,它是一种语法糖,要求在范围内有一个隐式的F [A]
。通常用于以比隐式参数((implicit fa:F [A])
)更简洁和易读的方式召唤类型类实例,但在幕后它仍然以完全相同的方式工作,正如Daniel所指出的那样,特质无法做到这一点。 - mirichan当一个trait被“sealed”(密封)时,所有子类都必须在同一个文件中声明,这使得子类的集合变为有限,从而允许进行某些编译器检查。
我还需要指向规范:
sealed修饰符适用于类定义。一个sealed类不能直接被继承,除非继承模板在与继承的类相同的源文件中定义。但是,密封类的子类可以被任何地方继承。
— M. Odersky. The Scala language specification, version 2.8. online, Sept., 2013.
简而言之:
更多详情请参见 Scala中关于密封特质的一切
case classes
来扩展。
普通特质和密封特质之间的核心区别可以总结如下:
普通特质是开放的,因此任何数量的类都可以继承该特质,只要它们提供了所有必需的方法,并且这些类的实例可以通过特质所需的方法互换使用。 普通特质层次结构使添加额外的子类变得容易:只需定义您的类并实现必要的方法。但是,添加新方法变得困难:需要将新方法添加到所有现有子类中,而现有子类可能有很多。
密封特质是封闭的:它们仅允许一组固定的类从中继承,并且所有继承类必须与特质本身一起在同一文件或REPL命令中定义。 密封特质层次结构相反:添加新方法很容易,因为新方法只需模式匹配每个子类并决定要为每个子类执行什么操作。但是,添加新子类很困难,因为您需要转到所有现有模式匹配并添加处理新子类的case。
例如:
object SealedTraits extends App{
sealed trait Point
case class Point2D(x: Double, y: Double) extends Point
case class Point3D(x: Double, y: Double, z: Double) extends Point
def hypotenuse(p: Point) = p match {
case Point2D(x, y) => math.sqrt(x x + y y)
case Point3D(x, y, z) => math.sqrt(x x + y y + z z)
}
val points: Array[Point] = Array(Point2D(1, 2), Point3D(4, 5, 6))
for (p <- points) println(hypotenuse(p))
// 2.23606797749979
// 8.774964387392123
JSON
。
JSON
只能是JSON
null、布尔值、数字、字符串、数组或字典。JSON
保持了20年的稳定,因此不太可能有人需要扩展我们的JSON
以添加其他子类。JSON
blob执行的操作范围是无限的:解析它、序列化它、漂亮地打印它、缩小它、消毒它等等。
因此,将JSON
数据结构建模为封闭的sealed trait层次结构而不是普通的开放的trait层次结构是有意义的。 sealed trait Json
case class Null() extends Json
case class Bool(value: Boolean) extends Json
case class Str(value: String) extends Json
case class Num(value: Double) extends Json
case class Arr(value: Seq[Json]) extends Json
case class Dict(value: Map[String, Json]) extends Json