1. Sealed Class
1.1 sealed class
先上一段代码,看看sealed是怎么使用的
scala> sealed abstract class Drawing defined class Drawing scala> case class Point(x: Int, y: Int) extends Drawing defined class Point scala> case class Circle(p: Point, r: Int) extends Drawing defined class Circle scala> case class Cylinder(c: Circle, h: Int) extends Drawing defined class Cylinder scala> def what(d: Drawing) = d match { | case Point(_,_) => "点" | case Circle(_,_) => "圆" | } <console>:16: warning: match may not be exhaustive. It would fail on the following input: Cylinder(_, _) def what(d: Drawing) = d match { ^ what: (d: Drawing)String
在这里what()方法报错了,主要是因为还缺少了对Cylinder的匹配,只要改成如下的代码就可以正常运行了。
scala> def what(d: Drawing) = d match { | case Point(_,_) => "点" | case Circle(_,_) => "圆" | case Cylinder(_,_) => "柱" | } what: (d: Drawing)String
在使用模式匹配的时候,使用 sealed 修饰某个 class 的目的是让 Scala 知道所有 case 的情况,否则会编译报错。
当然,也有例外的时候,使用 @unchecked 告诉编译器可以不用检查也能编译通过。
scala> def what(d: Drawing) = (d: @unchecked) match { | case Point(_,_) => "点" | case Circle(_,_) => "圆" | } what: (d: Drawing)String
还有一点很重要,当使用 sealed 来修饰某个 class 时,继承该类的其他子类需要跟父类在同一文件中。
1.2 sealed trait
同样,先上一段代码
scala> sealed trait Color defined trait Color scala> final case object Red extends Color defined object Red scala> final case object Green extends Color defined object Green scala> final case object Blue extends Color defined object Blue scala> val colors = List(Red,Green,Blue) colors: List[Product with Serializable with Color] = List(Red, Green, Blue)
可以看到“Product with Serializable with Color”这一句。
case class 会自动继承两个trait:Product 和 Serializable。
Product Trait 让 case class 被扩展为具有Algebraic Data Type,或者说具有产品类型。
Serializable Trait 让 case class 可以被视为一个纯粹的数据,能够被序列化。
如果你想避免看到这个实现的细节,可以提前声明Color已经扩展了 Product 和 Serializable 这些 trait。
scala> sealed trait Color extends Product with Serializable defined trait Color scala> final case object Red extends Color defined object Red scala> final case object Green extends Color defined object Green scala> final case object Blue extends Color defined object Blue scala> val colors = List(Red, Green, Blue) colors: List[Color] = List(Red, Green, Blue)
sealed 修饰的 trait 也只能在当前文件里面被继承。
1.3 sealed abstract 和 abstract class 的区别
sealed class的所有子类,无论是否是抽象类,都必须跟 sealed class 在同一个文件中。
而abstract class并没有这样的规定。
2. Enumeration
Scala 中并没有枚举类型,但是在标准库中有scala.Enumeration
。可以扩展Enumeration类,调用Value方法来初始化枚举中的可能值。
/** * Created by tony on 2017/4/12. */ object Source extends Enumeration { type Source = Value //枚举的定义 val Net, Memory, Disk = Value } import Source._ object Data extends App { def loadData(source: Source){ source match { case Net => println ("source type is " + source) case Memory => println ("source type is " + source) case Disk => println ("source type is " + source) case _ => println ("unknown type") } } val net = Source(0) // Calls Enumeration.apply println(loadData(net)) // source type is Net // 遍历Source枚举 for (s <- Source.values) println(s.id + ":" + s) }
打印的结果:
source type is Net () 0:Net 1:Memory 2:Disk
在定义枚举值的时候也可以自定义id和名称,Source2重新定义了几个枚举。
/** * Created by tony on 2017/4/12. */ object Source2 extends Enumeration { type Source = Value //枚举的定义 val Net, Memory, Disk = Value val Other = Value(10,"other source") } object Data2 extends App { // 遍历Source枚举 for (s <- Source2.values) println(s.id + ":" + s) }
打印的结果:
0:Net 1:Memory 2:Disk 10:other source
最终,我们可以得到:
- Scala中的枚举使用轻量级Enumeration进行实现
- Scala中的枚举其实是一个伴随对象
- Scala中的枚举没有方法重写功能
- Scala中的枚举其实都是Enumeration.Value这个对象
总结
本篇笔记仍然是为了 Scala 模式匹配所做的铺垫。在模式匹配中会讲到Sealed Class,所以先整理出来。除了Sealed用法之外,还整理了Enumeration的相关用法。