Scala的sealed关键字

缘起

今天在学习Akka的监控策咯过程中看到了下面一段代码:

  def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) {
case _: ArithmeticException => Resume
case _: IllegalArgumentException => Restart
case _: NullPointerException => Stop
case _: Exception => Escalate
}

当时有点好奇,就想去看看Resume, Restart等的实现,于是就看到了下面的代码:

object SupervisorStrategy extends SupervisorStrategyLowPriorityImplicits {

sealed trait Directive

/**
* Resumes message processing for the failed Actor
*/
case object Resume extends Directive /**
* Discards the old Actor instance and replaces it with a new,
* then resumes message processing.
*/
case object Restart extends Directive /**
* Stops the Actor
*/
case object Stop extends Directive /**
* Escalates the failure to the supervisor of the supervisor,
* by rethrowing the cause of the failure.
*/
case object Escalate extends Directive // ....
}

刚刚Scala不久,不太清楚这里的sealed关键字的作用,本文下面就详细的描述一下这个关键字的作用吧。

模式匹配

模式匹配pattern matching在scala里面是一个重量级的功能,依赖于模式匹配可以优雅地实现很多功能。大致格式如下:

selector match {
pattern1 => <body1>
pattern2 => <body2>
...
}

pattern总结起来大约以下几类:

  • Wildcard patterns // _ 统配
  • Constant patterns // 常量
  • Variable patterns // 变量
  • Constructor patterns // 构造函数
  • Sequence patterns // 比如List(,). 如果需要匹配剩余的话使用List(0,_*)
  • Tuple patterns // (a,b,c)
  • Typed patterns // 使用类型匹配 case a:Map[,]
  • asInstanceOf[]
  • isInstanceOf[]
  • note(dirlt):这里需要注意容器类型擦除.Array例外因为这个是java内置类型

实际上我们还能够使用pattern完成下面事情:

  • Patterns in variable definitions // val (a,b) = ("123","345");

  • Case sequences as partial functions

    • 直接使用pattern来构造函数.以参数为match对象,在body里面直接编写case.
    • Each case is an entry point to the function, and the parameters are specified with the pattern. The body of each entry point is the right-hand side of the case.
  • Patterns in for expressions // for ((country, city) <- capitals)

      // case sequences as partial function.
    val foo : Option[String] => String = {
    case Some(e) => e
    case None => "???"
    } val a = Option[String]("hello")
    println(foo(a))
    val b = None
    println(foo(b))

pattern matching过程中还有下面几个问题需要注意:

  • Patterns are tried in the order in which they are written.
  • Variable binding // 有时候我们希望匹配的变量包含外层结构
    • A(1,B(x)) => handle(B(x))
    • A(1, p @ B(_)) => handle(p) # p绑定了B(x)这个匹配
    • A(1, p @ B()) => handle(p) # B是可以包含unapply从type(p) => Boolean的类,做条件判断
  • Pattern guards // 有时候我们希望对pattern做一些限制性条件
    • A(1,e,e) 比如希望后面两个元素相等,但是这个在pm里面没有办法表达
    • A(1,x,y) if x == y => // 通过guard来完成

scala为了方便扩展模式匹配对象的case, 提供case class这个概念。case class和普通class大致相同,不过有以下三个区别,定义上只需要在class之前加上case即可:

  • 提供factory method来方便构造object

  • class parameter隐含val prefix

  • 自带toString,hashCode,equals实现

      case class A(x:Int) {} // implicit val x:Int
    val a = A(1); // factory method.
    println(a.x);
    println(a); // toString = A(1)

case class最大就是可以很方便地用来做pattern matching.

如果我们能够知道某个selector所有可能的pattern的话,那么就能够在编译期做一些安全性检查。但是selector这个过于宽泛,如果将selector限制在类层次上的话,那么还是可以实现的。举例如下:

abstract class A; // sealed abstract class A
case class B(a:Int) extends A;
case class C(a:Int) extends A;
case class D(a:Int) extends A; val a:A = B(1); a match {
case e @ B(_) => println(e)
case e @ C(_) => println(e)
}

在match a这个过程中,实际上我们可能存在B,C,D三种子类,但是因为我们这里缺少检查。使用sealed关键字可以完成这个工作。sealed class必须和subclass在同一个文件内。A sealed class cannot have any new subclasses added except the ones in the same file. 如果上面增加sealed的话,那么编译会出现如下警告,说明我们没有枚举所有可能的情况。

/Users/dirlt/scala/Hello.scala:8: warning: match may not be exhaustive.
It would fail on the following input: D(_)
a match {
^
one warning found

有三个方式可以解决这个问题,一个是加上对D的处理,一个是使用unchecked annotation, 一个则是在最后用wildcard匹配

    (a : @unchecked)  match {
case e @ B(_) => println(e)
case e @ C(_) => println(e)
} a match {
case e @ B(_) => println(e)
case e @ C(_) => println(e)
case _ => throw new RuntimeException("??");
}

sealed

从上面的描述我们可以知道,sealed 关键字主要有2个作用:

  • 其修饰的trait,class只能在当前文件里面被继承
  • 用sealed修饰这样做的目的是告诉scala编译器在检查模式匹配的时候,让scala知道这些case的所有情况,scala就能够在编译的时候进行检查,看你写的代码是否有没有漏掉什么没case到,减少编程的错误。

Scala的sealed关键字的更多相关文章

  1. C#中sealed关键字

    C#中sealed关键字 1. sealed关键字     当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承.类似于Java中final关键字.     在下面的示例中,类 B ...

  2. sealed关键字

    1. sealed关键字    当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承.类似于Java中final关键字.    在下面的示例中,类 B 从类 A 继承,但是任何类都不 ...

  3. scala类型系统 type关键字

    和c里的type有点像. scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型. type相当于声明一个类型别名: scala> t ...

  4. C#多态;父类引用指向子类对象;new和override的区别;new、abstract、virtual、override,sealed关键字区别和使用代码示例;c#类的初始化顺序

    关于父类引用指向子类对象 例如: 有以下2个类 public class Father { public int age = 70; public static string name = " ...

  5. scala 使用case 关键字定义类不需要创建对象直接调用

    1.必须是使用case 定义object类 package config import org.apache.spark.sql.SparkSession import org.apache.spar ...

  6. Scala 关键字

    Java关键字 Java 一共有 50 个关键字(keywords),其中有 2 个是保留字,目前还不曾用到:goto 和 const.true.false 和 null 看起来很像关键字,但实际上只 ...

  7. Scala学习之路 (五)Scala的关键字Lazy

    Scala中使用关键字lazy来定义惰性变量,实现延迟加载(懒加载). 惰性变量只能是不可变变量,并且只有在调用惰性变量时,才会去实例化这个变量. 在Java中,要实现延迟加载(懒加载),需要自己手动 ...

  8. Scala基础语法 (一)

    如果你之前是一名 Java 程序员,并了解 Java 语言的基础知识,那么你能很快学会 Scala 的基础语法. Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的. 我 ...

  9. scala(一)Nothing、Null、Unit、None 、null 、Nil理解

    相对于java的类型系统,scala无疑要复杂的多!也正是这复杂多变的类型系统才让OOP和FP完美的融合在了一起! Nothing: 如果直接在scala-library中搜索Nothing的话是找不 ...

随机推荐

  1. jboss eap 6.3 域(Domain)模式配置

    jboss提供了二种运行模式:standalone(独立运行模式).domain(域模式),日常开发中,使用standalone模式足已:但生产部署时,一个app,往往是部署在jboss集群环境中的, ...

  2. Angular权威指南学习笔记(转)

    http://www.cnblogs.com/lzhp/p/4000741.html 第一章.        初识Angular——Angular是MVW的Js框架. 第二章.        数据绑定 ...

  3. 流形学习之等距特征映射(Isomap)

    感觉是有很久没有回到博客园,发现自己辛苦写的博客都被别人不加转载的复制粘贴过去真的心塞,不过乐观如我,说明做了一点点东西,不至于太蠢,能帮人最好.回校做毕设,专心研究多流形学习方法,生出了考研的决心. ...

  4. QDir的mkdir和mkpath区别

    mkdir:上层目录不存在时,创建会失败.比如创建“c:\\test\test”,如果test不存在,那test也创建不了.目录已经存在时会返回false. mkpath:上层目录不存在也没关系,自动 ...

  5. Qt5 新特性

    Qt 5 已经临近发布,其最大的特点就是模块化.将原来庞大的模块更细分为不同的部分,同时,一个大版本的升级,当然少不了添加.删除各个功能类.文本简单介绍 Qt5 的特性,其具体内容来自 Qt5 官方 ...

  6. 理解Java接口

    作者:梅云罗链接:https://www.zhihu.com/question/20111251/answer/14760353来源:知乎著作权归作者所有,转载请联系作者获得授权. 接口只是一个规范, ...

  7. 揭秘Facebook首个数据中心:全球15亿用户的账户信息都在这里

      投递人 itwriter 发布于 2016-07-14 17:41 评论(0) 原文链接 [收藏]  对于 Facebook.Google 这种体量的科技公司而言,数据中心应该是处于军事级别的保密 ...

  8. matlab eps

    matlab eps eps是一个函数.当没有参数时默认参数是1.返回的是该参数的精度. 也就是说单个的eps实际上是eps(1),表示的是1的精度. 这里要说一下精度的概念.浮点数所能表示的数值范围 ...

  9. MVC中使用Ajax提交数据 Jquery Ajax方法传值到action

    Jquery Ajax方法传值到action <script type="text/javascript"> $(document).ready(function(){ ...

  10. Beta版本冲刺Day4

    会议讨论: 628:由于昨天的考试我们组目前只把项目放到了服务器上,配置Java环境遇到了问题.601:将一些原来的界面进行了修改,修改成了更加美观的外形. 528:进行一些还未完成得到功能,比如查询 ...