Scala 系列(十一)—— 模式匹配
一、模式匹配
Scala 支持模式匹配机制,可以代替 swith 语句、执行类型检查、以及支持析构表达式等。
1.1 更好的swith
Scala 不支持 swith,可以使用模式匹配 match...case 语法代替。但是 match 语句与 Java 中的 switch 有以下三点不同:
- Scala 中的 case 语句支持任何类型;而 Java 中 case 语句仅支持整型、枚举和字符串常量;
- Scala 中每个分支语句后面不需要写 break,因为在 case 语句中 break 是隐含的,默认就有;
- 在 Scala 中 match 语句是有返回值的,而 Java 中 switch 语句是没有返回值的。如下:
object ScalaApp extends App {
def matchTest(x: Int) = x match {
case 1 => "one"
case 2 => "two"
case _ if x > 9 && x < 100 => "两位数" //支持条件表达式 这被称为模式守卫
case _ => "other"
}
println(matchTest(1)) //输出 one
println(matchTest(10)) //输出 两位数
println(matchTest(200)) //输出 other
}
1.2 用作类型检查
object ScalaApp extends App {
def matchTest[T](x: T) = x match {
case x: Int => "数值型"
case x: String => "字符型"
case x: Float => "浮点型"
case _ => "other"
}
println(matchTest(1)) //输出 数值型
println(matchTest(10.3f)) //输出 浮点型
println(matchTest("str")) //输出 字符型
println(matchTest(2.1)) //输出 other
}
1.3 匹配数据结构
匹配元组示例:
object ScalaApp extends App {
def matchTest(x: Any) = x match {
case (0, _, _) => "匹配第一个元素为 0 的元组"
case (a, b, c) => println(a + "~" + b + "~" + c)
case _ => "other"
}
println(matchTest((0, 1, 2))) // 输出: 匹配第一个元素为 0 的元组
matchTest((1, 2, 3)) // 输出: 1~2~3
println(matchTest(Array(10, 11, 12, 14))) // 输出: other
}
匹配数组示例:
object ScalaApp extends App {
def matchTest[T](x: Array[T]) = x match {
case Array(0) => "匹配只有一个元素 0 的数组"
case Array(a, b) => println(a + "~" + b)
case Array(10, _*) => "第一个元素为 10 的数组"
case _ => "other"
}
println(matchTest(Array(0))) // 输出: 匹配只有一个元素 0 的数组
matchTest(Array(1, 2)) // 输出: 1~2
println(matchTest(Array(10, 11, 12))) // 输出: 第一个元素为 10 的数组
println(matchTest(Array(3, 2, 1))) // 输出: other
}
1.4 提取器
数组、列表和元组能使用模式匹配,都是依靠提取器 (extractor) 机制,它们伴生对象中定义了 unapply 或 unapplySeq 方法:
- unapply:用于提取固定数量的对象;
- unapplySeq:用于提取一个序列;
这里以数组为例,Array.scala 定义了 unapplySeq 方法:
def unapplySeq[T](x : scala.Array[T]) : scala.Option[scala.IndexedSeq[T]] = { /* compiled code */ }
unapplySeq 返回一个序列,包含数组中的所有值,这样在模式匹配时,才能知道对应位置上的值。
二、样例类
2.1 样例类
样例类是一种的特殊的类,它们被经过优化以用于模式匹配,样例类的声明比较简单,只需要在 class 前面加上关键字 case。下面给出一个样例类及其用于模式匹配的示例:
//声明一个抽象类
abstract class Person{}
// 样例类 Employee
case class Employee(name: String, age: Int, salary: Double) extends Person {}
// 样例类 Student
case class Student(name: String, age: Int) extends Person {}
当你声明样例类后,编译器自动进行以下配置:
- 构造器中每个参数都默认为
val; - 自动地生成
equals, hashCode, toString, copy等方法; - 伴生对象中自动生成
apply方法,使得可以不用 new 关键字就能构造出相应的对象; - 伴生对象中自动生成
unapply方法,以支持模式匹配。
除了上面的特征外,样例类和其他类相同,可以任意添加方法和字段,扩展它们。
2.3 用于模式匹配
样例的伴生对象中自动生成 unapply 方法,所以样例类可以支持模式匹配,使用如下:
object ScalaApp extends App {
def matchTest(person: Person) = person match {
case Student(name, _) => "student:" + name
case Employee(_, _, salary) => "employee salary:" + salary
case _ => "other"
}
println(matchTest(Student("heibai", 12))) //输出: student:heibai
println(matchTest(Employee("ying", 22, 999999))) //输出: employee salary:999999.0
}
参考资料
- Martin Odersky . Scala 编程 (第 3 版)[M] . 电子工业出版社 . 2018-1-1
- 凯.S.霍斯特曼 . 快学 Scala(第 2 版)[M] . 电子工业出版社 . 2017-7
更多大数据系列文章可以参见 GitHub 开源项目: 大数据入门指南
Scala 系列(十一)—— 模式匹配的更多相关文章
- scala 系列文章汇总
本文作为scala系列文章索引 本博客目录: case class 背后的秘密 以spark源码为参照分析模式匹配及种类 另外,本文还收录了几个作者认为比较好的博文或网站: scala 相关网址汇总 ...
- Scala 系列(七)—— 常用集合类型之 Map & Tuple
一.映射(Map) 1.1 构造Map // 初始化一个空 map val scores01 = new HashMap[String, Int] // 从指定的值初始化 Map(方式一) val s ...
- SQL Server 2008空间数据应用系列十一:提取MapInfo地图数据中的空间数据解决方案
原文:SQL Server 2008空间数据应用系列十一:提取MapInfo地图数据中的空间数据解决方案 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Serv ...
- java基础解析系列(十一)---equals、==和hashcode方法
java基础解析系列(十一)---equals.==和hashcode方法 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系 ...
- 第74讲:从Spark源码的角度思考Scala中的模式匹配
今天跟随王老师学习了从源码角度去分析scala中的模式匹配的功能.让我们看看源码中的这一段模式匹配: 从代码中我们可以看到,case RegisterWorker(id,workerHost,.... ...
- Scala 经典的模式匹配和尾递归
Scala 经典的模式匹配和尾递归 package io import java.io.{BufferedWriter, File, FileWriter} import java.text.Simp ...
- (数据科学学习手札49)Scala中的模式匹配
一.简介 Scala中的模式匹配类似Java中的switch语句,且更加稳健,本文就将针对Scala中模式匹配的一些基本实例进行介绍: 二.Scala中的模式匹配 2.1 基本格式 Scala中模式匹 ...
- Scala基础:模式匹配和样例类
模式匹配 package com.zy.scala import scala.util.Random /** * 模式匹配 */ object CaseDemo { def main(args: Ar ...
- struts2官方 中文教程 系列十一:使用XML进行表单验证
在本教程中,我们将讨论如何使用Struts 2的XML验证方法来验证表单字段中用户的输入.在前面的教程中,我们讨论了在Action类中使用validate方法验证用户的输入.使用单独的XML验证文件让 ...
- 爬虫系列(十一) 用requests和xpath爬取豆瓣电影评论
这篇文章,我们继续利用 requests 和 xpath 爬取豆瓣电影的短评,下面还是先贴上效果图: 1.网页分析 (1)翻页 我们还是使用 Chrome 浏览器打开豆瓣电影中某一部电影的评论进行分析 ...
随机推荐
- Python使用进程间共享变量来控制两个进程(监听键盘和相机录制)的交互
我有个简单的应用需求: 1. 该应用随时会监听键盘的输入: 2. 当输入指定键时会控制相机录制的启动和关闭. 监听键盘是一个事件循环,相机录制也是一个循环录制的过程.我试着用 Python 启动两个进 ...
- 在K8S集群中使用busybox-dig镜像,来作DNS解析分析
以前,判断K8S里的DNS功能是否正常时,得想很多办法. 如果有了busybox-dig镜像,则作这事就简单多了. 如下命令,直接部署 kubectl run busybox -it --image= ...
- texlive相关问题
1.The font "WenQuanYi Micro Hei" cannot be found. 解决方法:下载WenQuanYi Micro Hei的字体(以ttf结尾),粘贴 ...
- CentOS6.10部署的Tomcat8.5启动后,浏览器访问不到的解决方法
解决过程如下: 一.关闭 selinux 和 iptables 防火墙 二.查看 tomcat 是否在运行 ps aux |grep tomcat 三.查看端口情况 lsof -i:8080 查看后都 ...
- 数据库中的gt,ge,lt,le的区别
eq相等 ne.neq不相等, gt大于, lt小于 gte.ge大于等于 lte.le 小于等于 not非 mod求模 is [not] div by是否能被某数整除 i ...
- redis常用操作(测试必备)
连接redis redis的安装及基础配置,参考:https://www.cnblogs.com/UncleYong/p/9882843.html redis中,数据是key-value方式存储,ke ...
- 什么是amp?amp有什么用处?
AMP是移动页面加速器Accelerated Mobile Pages的简称,是Google带领开发的开源项目,目的是为提升移动设备对网站的访问速度.它的核心称作AMP HTML,是一种新型的HTML ...
- JavaScript词法作用域—你不知道的JavaScript上卷读书笔记(一)
前段时间在每天往返的地铁上抽空将 <你不知道的JavaScript(上卷)>读了一遍,这本书很多部分写的很是精妙,对于接触前端时间不太久的人来说,就好像是叩开了JavaScript的另一扇 ...
- 7.Go退出向Consuk反注册服务,优雅关闭服务
注册和反注册代码 package utils import ( consulapi "github.com/hashicorp/consul/api" "log" ...
- 异常CLRDBG_NOTIFICATION_EXCEPTION_CODE( 0x04242420)的抛出过程
新建一个c#控制工程,就用自动生成的代码,不用补任何代码,如下: using System; using System.Collections.Generic; using System.Linq; ...