Scala学习文档-样本类与模式匹配(match,case,Option)
样本类:添加了case的类便是样本类。这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定。
//样本类case class
//层级包括一个抽象基类Expr和四个子类,每个代表一种表达式
//样本类自动添加与类名一致的工厂方法
abstract class Expr
case class Var(name:String) extends Expr//括号内参数不用加val,默认为加val的字段
case class Number(num:Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String, left:Expr,right:Expr)extends Expr
def main(args:Array[String]):Unit = {
//1、样本类自动添加与类名一致的工厂方法,所以可以不用new就构造出相应对象
val v = Var("x");
val op = BinOp("+",Number(1.0),v);
//2、样本类参数列表中的所有参数隐式获得了val前缀,构造器中的每一个参数都成为val,除非显式生命为var(不建议)
var s1:String = v.name
//3、此外将生成toString equals hashCode copy方法,除非显式定义
//除上述外,样例类与其他类完全一样
//============================================================//
//match对应于Java里的Switch
//选择器 match{备选项} 取代了 switch{选择器}{备选项}
//一个备选项包含了一个模式以及多个表达式,箭头符号=>隔开了模式与表达式
//本函数不对表达式进行任何的改变,只用来返回用来做匹配的表达式expr
def simplifyTop(expr:Expr):Expr = expr match{
case UnOp("-",UnOp("-",e)) =>e
case BinOp("+",e,Number(0))=>e
case BinOp("*",e,Number(1))=>e
case _ => expr //如果没有通配, 在匹配不到的时候抛出异常
}
println(simplifyTop(BinOp("+",v,Number(0))))
println(simplifyTop(BinOp("*",op,Number(1))))
}
模式匹配:
match与switch的比较:匹配表达式可以被看作Java风格Switch的泛化。但有三点不同:
- match是Scala的表达式,始终以值作为结果;
- Scala的备选项表达式永远不会“掉到”下一个case;
- 如果没有模式匹配,MatchError异常会被抛出。这意味着必须始终确信所有的情况都考虑到了,或者至少添加一个默认情况什么都不做。如 case _ =>
模式的种类
通配模式
通配模式_匹配任意对象,也可以用来忽略对象中不关心的部分
常量模式
常量模式仅仅匹配自身。任何字面量都可以作为常量
变量模式
变量模式类似于通配符,可以匹配任何对象。不同点在于,Scala把变量绑定在匹配的对象上。之后就可以使用这个变量操作对象。如:
def pipei (x:Any) = {
x match{
case 0 => "zero" //常量模式
case somethingElse => "not zero" + somethingElse //变量模式
}
}
构造器模式
它的存在使得模式匹配真正变得强大。它由名称及若干括号之内的模式构成。如BinOp("+" , e , Number(0))
序列模式
可以像匹配样本类那样匹配List或Array这样的序列类型。同样的语法现在可以指定模式内任意数量的元素。如:
val myList = List(1,1,2,3)
def findL(l1:List[Int]):Unit={
l1 match{
case List(0,1,_,_) =>println("找到了!");
case _ =>println("没找到!");
}
}
findL(myList)
如果想匹配一个不指定长度的序列,可以指定_*作为模式的最后元素。它能匹配序列中0到任意数量的元素。
元组模式
def tupleDemo(expr : Any) =
expr match {
case (a , b, c) => println("matched " + a + b + c)
case _ =>
}
类型模式:可以把它当做类型测试和类型转换的简易替代。例如:
def generalSize(x : Any) = x match{
case s : String => s.length
case m : Map[_ , _] => m.size
case _ => 1
}
使用: scala> generalSize(Map(1 -> 'a' , 2 -> 'b'))
res15 : Int = 2
另:在Scala里类型测试和转换的代码很冗长,因为不建议这么做。
模式守卫:
模式变量仅允许在模式中出现一次。如:
case BinOp("+" , x , x ) => BinOp("*" , x , Number(2))
这种写法就会出错。可以改成: case BinOp("+" , x , y ) if x == y => BinOp("*" , x , Number(2))
模式守卫接在模式之后,开始于if。守卫可以是任意的引用模式中变量的布尔表达式。如果存在模式守卫,那么只有在守卫返回true的时候匹配才成功。
类型擦除:
def isIntMap(x:Any)={
x match{
case m: Map[Int,Int]=>true
case _ =>false
}
}
val m1 =Map(1->11,2->22)
val m2 = Map("s1"->"sss111")
println(isIntMap(m1))
println(isIntMap(m2))
打印出 true
true
第一个true看起来正确,第二个true看起来不合理,因为只能判断出是某种参数类型的Map,而不能判断出参数类型
擦除规则的唯一例外就是数组。
//数组的类型,不擦除
def isStringArray(x:Any)={
x match{
case s:Array[String]=>true
case _=> false
}
}
val a1 = Array("aa","bb")
val a2 = Array[Int](1,2)
println(isStringArray(a1))
println(isStringArray(a2))
打印出 true
false
变量绑定
如果匹配成功,把变量设置成匹配的对象
//变量绑定
def doubleABS(expr:Expr)={
expr match{
case UnOp("abs",e @ UnOp("abs",_))=>e //相当于把UnOp("abs",_)绑定到e,以便后面使用
case _ =>
}
}
val e1 = UnOp("abs",UnOp("abs",v))
println(doubleABS(e1))
输出:UnOp(abs,Var(x))
模式守卫
模式守卫开始于if 只有在守卫返回true时匹配才成功。
//模式守卫
def simplifyAdd(expr:Expr)={
expr match{
//case BinOp("+",x,x)=>BinOp("*",x,Number(2))错误,不能有两个x,模式变量仅允许在模式中出现一次
case BinOp("+",x,y) if(x==y )=>BinOp("*",x,Number(2))
case _=>expr
}
}
封闭类
sealed abstract class Expr //加上sealed 代表封闭类
case class Var(name:String) extends Expr//括号内参数不用加val,默认为加val的字段
case class Number(num:Double) extends Expr
case class UnOp(operator: String, arg: Expr) extends Expr
case class BinOp(operator: String, left:Expr,right:Expr)extends Expr
//封闭类除了类定义所在的文件之外,不能再添加任何新的子类。
//如果使用继承自封闭类的样本类做匹配,若缺失了某种模式组合,编译器将警告
//封闭类的使用
def fengbi(expr:Expr)={
expr match{ //有警告标志,因为丢失了可能样本的模式匹配
case BinOp("+",e,y)=>e;
}
}
编译后的警告
Description Resource Path Location Type
match may not be exhaustive.
It would fail on the following inputs:
BinOp((x: String forSome x not in "+"), _, _), Expr(), Number(_), UnOp(_, _), Var(_)
Test1.scala /test14/src/com/evor/test14 line 93 Scala Problem
Option类型
def main(args:Array[String]):Unit = {
val captials = Map("China"->"Beijing","France"->"Paris")
val c = captials.get("China") //get方法返回可选值,Map的get方法在找到指定键时返回Some(value),否则返回None
val a = captials.get("Americas")
println(c)
println(a)
def show(x:Option[String])={ //通过模式匹配,分离可选值
x match{
case Some(s)=>s
case None=> "Don't know." //如果可选类型为None 返回don't know
}
}
println(show(c))
println(show(a))
}
运行结果:
Some(Beijing)
None
Beijing
Don't know.
Scala学习文档-样本类与模式匹配(match,case,Option)的更多相关文章
- Scala学习文档-列表的使用
注:列表是不可变的,不能通过赋值改变列表的元素 列表具有递归结构,数组是连续的 scala里的列表类型是协变的? --> scala中的逆变与协变 分治原则 //自定义实现:::操作符 def ...
- Scala学习文档-各种使用模式的情况
模式在变量定义中 在定义val或者var的时候,可以使用模式替代简单的标识符,如可以使用模式拆分元组,并把每个值分配给变量 val myTuple = (123,"abc") va ...
- Scala学习文档-访问修饰符
在scala里,对保护成员的访问比Java严格.Scala中,保护成员只在定义了成员的类的子类中可以访问,而Java中,还允许在同一个包的其他类中访问. package p1 { class FCla ...
- scala学习笔记(四)样本类与模式匹配
访问修饰符 格式:private[x]或protected[x],x指某个所属包.类或单例对象,表示被修饰的类(或方法.单例对象),在X域中公开,在x域范围内都可以访问: private[包名]:在该 ...
- 2013 最新的 play web framework 版本 1.2.3 框架学习文档整理
Play framework框架学习文档 Play framework框架学习文档 1 一.什么是Playframework 3 二.playframework框架的优点 4 三.Play Frame ...
- soapUI学习文档(转载)
soapUI 学习文档不是前言的前言记得一个搞开发的同事突然跑来叫能不能做个WebService 性能测试,当时我就凌乱了,不淡定啊,因为我是做测试的,以前连WebService 是什么不知道,毕竟咱 ...
- Spark样本类与模式匹配
一.前言 样本类(case class)与模式匹配(pattern matching)是Scala中一个比较复杂的概念,往往让人感觉深陷泥沼.我在这里对Scala中的样本类与模式匹配进行了一些整理,希 ...
- Ext JS 6学习文档-第8章-主题和响应式设计
Ext JS 6学习文档-第8章-主题和响应式设计 主题和响应式设计 本章重点在 ExtJS 应用的主题和响应式设计.主要有以下几点内容: SASS 介绍和入门 主题 响应式设计 SASS 介绍和入门 ...
- Ext JS 6学习文档-第6章-高级组件
Ext JS 6学习文档-第6章-高级组件 高级组件 本章涵盖了高级组件,比如 tree 和 data view.它将为读者呈现一个示例项目为 图片浏览器,它使用 tree 和 data view 组 ...
随机推荐
- 调用Android系统设置中的Intent
开发Android软件时,常常需要打开系统设置或信息界面,来设置相关系统项或查看系统的相关信息,这时我们就可以使用以下语句来实现:(如打开“无线和网络设置”界面) Intent intent = ne ...
- Linux 杀死挂起的进程
在用管理员执行一个命令后,用Ctrl+Z把命令转移到了后天.导致无法退出root的. 输入命令:exit终端显示:There are stopped jobs. 解决方法:方法一.输入命令:jobs终 ...
- 回收带Lob字段表占用的空间
SQL> select object_name from user_objects; no rows selected SQL> select segment_name from user ...
- 【剑指offer】面试题39扩展:平衡二叉树
题目: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 思路: 直观的思路是,判断根结点的左子树.右子树高度差是否小于1. 为避免多次访问同一结点,应该用后序遍历的方式访问. 注意:加号优先级高于条件 ...
- Decorator学习笔记
初学者,自己的理解,请各位前辈不吝指正! Decorator,装饰模式,设计模式之一,谈谈我的理解,装饰这个词在我概念中就是给某个事物加上一些美丽的外表,把它变得更加完美.但是装饰是可以随时改变的,可 ...
- H5页面音频自动播放问题
最近有这么一个需求,需要在手机加载一个页面的时候,自动播放音乐资源.一般情况下,这个问题也就解决了,但是要保证各种手机上表现一致,那就相当困难了,至少要费点儿周折. 下面有三种常规 ...
- Hadoop 2、配置HDFS HA (高可用)
前提条件 先搭建 http://www.cnblogs.com/raphael5200/p/5152004.html 的环境,然后在其基础上进行修改 一.安装Zookeeper 由于环境有限,所以在仅 ...
- 1042. Shuffling Machine (20) - sstream实现数字转字符串
题目例如以下: Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffli ...
- [RxJS] Displaying Initial Data with StartWith
You often need to render out data before you stream begins from a click or another user interaction. ...
- spring 通过工厂方法配置Bean
概要: 通过调用静态工厂方法创建Bean 调用静态工厂方法创建Bean是将对象创建的过程封装到静态方法中.当client须要对象时,仅仅须要简单地调用静态方法,而不用关心创建对象地细节. 要声明通过静 ...