12. Scala模式匹配
12.1 match
12.1.1 基本介绍
Scala中的模式匹配类似于Java中的switch语法,但是更加强大
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有的case都不匹配,那么会执行case_分支,类似于Java中的default语句
12.1.2 scala的match的快速入门案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val oper = '+'
- val n1 = 20
- val n2 = 10
- var res = 0
- //说明
- //1. match (类似java switch) 和 case 是关键字
- //2. 如果匹配成功, 则 执行 => 后面的代码块.
- //3. 匹配的顺序是从上到下,匹配到一个就执行对应的 代码
- //4. => 后面的代码块 不要写 break ,会自动的退出match
- //5. 如果一个都没有匹配到,则执行 case _ 后面的代码块
- oper match {
- case '+' => {
- res = n1 + n2
- println("ok~~")
- println("hello~~")
- }
- case '-' => res = n1 - n2
- case '*' => res = n1 * n2
- case '/' => res = n1 / n2
- case 1 => println("匹配到1")
- case 1.1 => println("匹配1.1")
- case _ => println("oper error")
- }
- println("res=" + res)
- }
- }
12.1.3 match的细节和注意事项
1) 如果所有case都不匹配,那么会执行case_分支,类似于Java中的default语句
2) 如果所有case都不匹配,又没有写case_分支,那么会抛出MatchError
3) 每个case中,不用break语句,自动中断case
4) 可以在match中使用其它类型,而不仅仅是字符
5) => 等价于 java switch的 :
6) => 后面的代码块到下一个case,是作为一个整体执行,可以使用{}扩起来,也可以不扩
12.2 守卫
12.2.1 基本介绍
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫
12.2.2 应用案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- for (ch <- "+-3!") { //是对"+-3!" 遍历
- var sign = 0
- var digit = 0
- ch match {
- case '+' => sign = 1
- case '-' => sign = -1
- // 说明..
- // 如果 case 后有 条件守卫即if ,那么这时的 _ 不是表示默认匹配
- // 表示忽略 传入 的 ch
- case _ if ch.toString.equals("3") => digit = 3
- case _ => sign = 2
- }
- //分析
- // + 1 0
- // - -1 0
- // 3 0 3
- // ! 2 0
- println(ch + " " + sign + " " + digit)
- }
- }
- }
12.3 模式中的变量
12.3.1 基本介绍
如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量
12.3.2 应用案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val ch = 'U'
- ch match {
- case '+' => println("ok~")
- // 下面 case mychar 含义是 mychar = ch
- case mychar => println("ok~" + mychar)
- case _ => println("ok~~")
- }
- val ch1 = '+'
- //match是一个表达式,因此可以有返回值
- //返回值就是匹配到的代码块的最后一句话的值
- val res = ch1 match {
- case '+' => ch1 + " hello "
- case _ => println("ok~~")
- }
- println("res=" + res)
- }
- }
12.4 类型匹配
12.4.1 基本介绍
可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf
12.4.2 应用案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val a = 8
- //说明 obj 实例的类型 根据 a 的值来返回
- val obj = if (a == 1) 1
- else if (a == 2) "2"
- else if (a == 3) BigInt(3)
- else if (a == 4) Map("aa" -> 1)
- else if (a == 5) Map(1 -> "aa")
- else if (a == 6) Array(1, 2, 3)
- else if (a == 7) Array("aa", 1)
- else if (a == 8) Array("aa")
- //说明
- //1. 根据 obj 的类型来匹配
- // 返回值
- val result = obj match {
- case a: Int => a
- case b: Map[String, Int] => "对象是一个字符串-数字的Map集合"
- case c: Map[Int, String] => "对象是一个数字-字符串的Map集合"
- case d: Array[String] => d //"对象是一个字符串数组"
- case e: Array[Int] => "对象是一个数字数组"
- case f: BigInt => Int.MaxValue
- case y: Float => println("xx")
- case _ => "啥也不是"
- }
- println(result)
- }
- }
12.4.3 类型匹配注意事项
1) Map[String, Int]和Map[Int, String]是两种不同的类型,其它类推
2) 在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val obj = 10
- val result = obj match {
- case a: Int => a
- //case b: Map[String, Int] => "Map集合" //取消注释之后会报错
- case _ => "啥也不是"
- }
- }
- }
4) 如果case _ 出现在match中间,则表示隐藏变量名,即不使用,而不是表示默认匹配
12.5 匹配数组
12.5.1 基本介绍
1) Array(0)匹配只有一个元素且为0的数组
2) Array(x,y)匹配数组有两个元素,并将两个元素赋值为x和y。当然可以依次类推Array(x,y,z)匹配数组有三个元素,等等
3) Array(0,_*)匹配数组以0开始
12.5.2 应用案例
- import scala.collection.mutable.ArrayBuffer
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- // val arrs = Array(Array(0), Array(1, 0), Array(0, 1, 0),
- // Array(1, 1, 0), Array(1, 1, 0, 1))
- //
- // for (arr <- arrs ) {
- // val result = arr match {
- // case Array(0) => "0"
- // case Array(x, y) => x + "=" + y
- // case Array(0, _*) => "以0开头和数组"
- // case _ => "什么集合都不是"
- // }
- // // result = 0
- // // result = 1 = 0
- // // result = 以0开头和数组
- // // result = 什么集合都不是
- // // result = 什么集合都不是
- // println("result = " + result)
- // }
- //给你一个数组集合,如果该数组是 Array(10,20) , 请使用默认匹配,返回Array(20,10)
- val arrs2 = Array(Array(0), Array(1, 0), Array(0, 1, 0),
- Array(1, 1, 0), Array(1, 1, 0, 1))
- for (arr <- arrs2) {
- val result = arr match {
- //case Array(0) => "0"
- case Array(x, y) => ArrayBuffer(y, x) //Array(y,x).toBuffer //? ArrayB(y,x)
- //case Array(0, _*) => "以0开头和数组"
- case _ => "不处理~~"
- }
- println("res=" + result) //ArrayBuffer(0,1)
- }
- }
- }
12.6 匹配列表
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
- val result = list match {
- case 0 :: Nil => "0" //
- case x :: y :: Nil => x + " " + y //
- case 0 :: tail => "0 ..." //
- case x :: Nil => x
- case _ => "something else"
- }
- //1. 0
- //2. 1 0
- //3. 0 ...
- //4. something else
- println(result)
- }
- }
- }
12.7 匹配元组
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- //如果要匹配 (10, 30) 这样任意两个元素的对偶元组,应该如何写
- for (pair <- Array((0, 1), (1, 0), (10, 30), (1, 1), (1, 0, 2))) {
- val result = pair match { //
- case (0, _) => "0 ..." //
- case (y, 0) => y //
- case (x, y) => (y, x) //"匹配到(x,y)" + x + " " + y
- case _ => "other" //.
- }
- //1. 0 ...
- //2. 1
- //3. (30,10)
- //4. (1,1)
- //5. other
- println(result)
- }
- }
- }
12.8 对象匹配
12.8.1 基本介绍
对象匹配,什么才算是匹配呢?规则如下:
1) case中对象的unapply方法(对象提取器)返回Some集合则为匹配成功
2) 返回None集合则为匹配失败
12.8.2 快速入门
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- // 模式匹配使用:
- val number: Double = Square(6.0) // 36.0 //
- number match {
- //说明 case Square(n) 的运行的机制
- //1. 当匹配到 case Square(n)
- //2. 调用Square 的 unapply(z: Double),z 的值就是 number
- //3. 如果对象提取器 unapply(z: Double) 返回的是Some(6) ,则表示匹配成功,同时
- // 将6 赋给 Square(n) 的n
- //4. 果对象提取器 unapply(z: Double) 返回的是None ,则表示匹配不成功
- case Square(n) => println("匹配成功 n=" + n)
- case _ => println("nothing matched")
- }
- }
- }
- //说明
- object Square {
- //说明
- //1. unapply方法是对象提取器
- //2. 接收z:Double 类型
- //3. 返回类型是Option[Double]
- //4. 返回的值是 Some(math.sqrt(z)) 返回z的开平方的值,并放入到Some(x)
- def unapply(z: Double): Option[Double] = {
- println("unapply被调用 z 是=" + z)
- Some(math.sqrt(z))
- //None
- }
- def apply(z: Double): Double = z * z
- }
12.8.3 应用案例2
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val namesString = "Alice,Tom,Jack" //字符串
- //说明
- namesString match {
- // 当 执行 case Names(first, second, third)
- // 1. 会调用 unapplySeq(str),把 "Alice,Tom,Jack" 传入给 str
- // 2. 如果 返回的是 Some("Alice","Tom","Jack"),分别给 (first, second, third)
- // 注意,这里的返回的值的个数需要和 (first, second, third)要一样
- // 3. 如果返回的None ,表示匹配失败
- case Names(first, second, third) => {
- println("the string contains three people's names")
- // 打印字符串
- println(s"$first $second $third")
- }
- case _ => println("nothing matched")
- }
- }
- }
- //object
- object Names {
- //当构造器是多个参数时,就会触发这个对象提取器
- def unapplySeq(str: String): Option[Seq[String]] = {
- if (str.contains(",")) Some(str.split(","))
- else None
- }
- }
-案例演示小结
1) 当case后面的对象提取器方法的参数为多个,则会默认调用def unapplySeq()方法
2) 如果unapplySeq返回的是Some,获取其中的值,判断得到的sequence中的元素的个数是否是三个,如果是三个,则把三个元素分别取出,赋值给first,second和third
3) 其它的规则不变
12.9 变量声明中的模式
12.9.1 基本介绍
match中每一个case都可以单独取出来,意思是一样的
12.9.2 应用案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val (x, y, z) = (1, 2, "hello")
- println("x=" + x)
- val (q, r) = BigInt(10) /% 3 //说明 q = BigInt(10) / 3 r = BigInt(10) % 3
- val arr = Array(1, 7, 2, 9)
- val Array(first, second, _*) = arr // 提出arr的前两个元素
- println(first, second)
- }
- }
12.10 for表达式中的模式
12.10.1 基本介绍
for循环也可以进行模式匹配
12.10.2 应用案例
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
- for ((k, v) <- map) {
- println(k + " -> " + v) // 出来三个key-value ("A"->1), ("B"->0), ("C"->3)
- }
- //说明 : 只遍历出 value =0 的key-value ,其它的过滤掉
- println("--------------(k, 0) <- map-------------------")
- for ((k, 0) <- map) {
- println(k + " --> " + 0)
- }
- //说明, 这个就是上面代码的另外写法, 只是下面的用法灵活和强大
- println("--------------(k, v) <- map if v == 0-------------------")
- for ((k, v) <- map if v >= 1) {
- println(k + " ---> " + v)
- }
- }
- }
12.11 样例(模版)类
12.11.1 样例类快速入门
- object CaseClassDemo01 {
- def main(args: Array[String]): Unit = {
- println("hello~~")
- }
- }
- abstract class Amount
- case class Dollar(value: Double) extends Amount //样例类
- case class Currency(value: Double, unit: String) extends Amount //样例类
- case object NoAmount extends Amount //样例类
12.11.2 基本介绍
1) 样例类仍然是类
2) 样例类用case关键字进行声明
3) 样例类是为模式匹配而优化的类
4) 构造器中的每一个参数都成为val-除非它被显式地声明为var(不建议这样做)
5) 在样例类对应的伴生对象中提供apply方法,不用new关键字就能构造出相应的对象
6) 提供unapply方法让模式匹配可以工作
7) 将自动生成toString、equals、hashCode和copy方法(有点类似模版类,直接给生成,供程序员使用)
8) 除上述外,样例类和其它类完全一样。可以添加字段和方法,扩展它们
12.11.3 应用案例1
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- //该案例的作用就是体验使用样例类方式进行对象匹配简洁性
- for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
- val result = amt match {
- //说明
- case Dollar(v) => "$" + v // $1000.0
- //说明
- case Currency(v, u) => v + " " + u // 1000.0 RMB
- case NoAmount => "NoAmount" // NoAmount
- }
- println(amt + ": " + result)
- }
- }
- }
- abstract class Amount
- case class Dollar(value: Double) extends Amount //样例类
- case class Currency(value: Double, unit: String) extends Amount //样例类
- case object NoAmount extends Amount //样例类
12.11.4 应用案例2
-说明
样例类的copy方法和带名参数
copy创建一个与现有对象值相同的新对象,并可以通过带名参数来修改某些属性
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- val amt = new Currency(3000.0, "RMB")
- val amt2 = amt.copy() // 克隆,创建的对象和amt的属性一样
- println("amt2.value" + amt2.value + " amt2.unit= " + amt2.unit)
- println(amt2)
- val amt3 = amt.copy(value = 8000.0)
- println(amt3)
- val amt4 = amt.copy(unit = "美元")
- println(amt4)
- }
- }
- abstract class Amount
- case class Dollar(value: Double) extends Amount //样例类
- case class Currency(value: Double, unit: String) extends Amount //样例类
- case object NoAmount extends Amount //样例类
12.12 case语句的中置(缀)表达式
12.12.1 基本介绍
什么是中置表达式?1 + 2,这就是一个中置表达式。如果unapply方法产出一个元组,可以在case语句中使用中置表示法。比如可以匹配一个List序列
12.12.2 应用案例
-案例演示
- object boke_demo01 {
- def main(args: Array[String]): Unit = {
- List(1, 3, 5, 9) match { //修改并测试
- //1.两个元素间::叫中置表达式,至少first,second两个匹配才行.
- //2.first 匹配第一个 second 匹配第二个, rest 匹配剩余部分(5,9)
- case first :: second :: rest => println(first + " " + second + " " + rest.length + " " + rest) //
- case _ => println("匹配不到...")
- }
- }
- }
12.13 密封类
12.13.1 基本介绍
1) 如果想让case类的所有子类都必须在申明该类的相同的源文件中定义,可以将样例类的通用超类声明为sealed,这个超类称之为密封类
2) 密封就是不能在其它文件中定义子类
12. Scala模式匹配的更多相关文章
- scala模式匹配的使用
Scala模式匹配 Tip1:模式总是从上往下匹配,如果匹配不到则匹配case_项(类似Java中的default) Tip2:与Java和C语言不同,不需要在每个分支末尾使用break语句退出(不会 ...
- scala模式匹配详细解析
一.scala模式匹配(pattern matching) pattern matching可以说是scala中十分强大的一个语言特性,当然这不是scala独有的,但这不妨碍它成为scala的语言的一 ...
- Spark记录-Scala模式匹配
Scala模式匹配 模式匹配是Scala函数值和闭包后第二大应用功能.Scala为模式匹配提供了极大的支持,处理消息. 模式匹配包括一系列备选项,每个替代项以关键字大小写为单位.每个替代方案包括一个模 ...
- 强大的Scala模式匹配
用过Scala的模式匹配,感觉Java的弱爆了.Scala几乎可以匹配任何数据类型,如果默认的不能满足你的要求,你可以自定义模式匹配. 介绍Scala的模式匹配前,我们先了解清楚unapply()与u ...
- scala模式匹配
package com.ming.test /** * 模式匹配 */ object MatchTest { def main(args: Array[String]): Unit = { //mat ...
- Scala模式匹配和类型系统
1.模式匹配比java中的switch case强大很多,除了值,类型,集合等进行匹配,最常见的Case class进行匹配,Master.scala有大量的模式匹配. Case "_&qu ...
- scala模式匹配与样例类
样本类:添加了case的类便是样本类.这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定.如下: 1.添加与类名一致的工厂方法.也就是说,可以写成Var("x") ...
- Scala模式匹配| 隐式转换
1. 模式匹配 Scala中的模式匹配类似于Java中的switch语法,但是更加强大.模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分 ...
- scala 模式匹配详解 3 模式匹配的核心功能是解构
http://www.artima.com/scalazine/articles/pattern_matching.html这篇文章是odersky谈scala中的模式匹配的一段对话,我做了部分片段翻 ...
随机推荐
- Jenkins 任务定时
在项目配置中选择 Build Triggers 下勾选 Build periodically,可以对项目进行定时构建设置.构建设置详细可通过右边的问号符号进行查看. 定时构建字段遵循 cron 的语法 ...
- 第一部分day03-元组、字典、字符串
-----元组-----元组查询 a = (1,2,3,4) print(a[1:2]) #(2,) 购物车练习(列表方法练习) product_list=[ ['Mac',9000], ['kind ...
- 目标检测论文解读12——RetinaNet
引言 这篇论文深刻分析了one-stage的模型精度比two-stage更差的原因,并提出Focal Loss提高精度. 思路 在论文中,作者指出,造成one-stage模型精度差的原因主要是:正负样 ...
- Java精通并发-Condition编程模式详解与分析
继续上一次https://www.cnblogs.com/webor2006/p/11890688.html的Condition接口说明进行阅读: 上面这个程序会在之后手动来实现一下,说实话这种写法在 ...
- win10锁屏壁纸文件夹位置
Win10默认系统下载的壁纸怎么下载?在哪里找出来呢?首先我们要把系统的锁屏壁纸要设置为Windows聚焦才会自动从微软的服务器上去下载壁纸.这些都是随机下载的.每个人的都Win10 都有可能不一样. ...
- Java多线程编程核心技术-第4章-Lock的使用-读书笔记
第 4 章 Lock 的使用 本章主要内容 ReentrantLocal 类的使用. ReentrantReadWriteLock 类的使用. 4.1 使用 ReentrantLock 类 在 Jav ...
- 在liuunex下部署 springBoot项目
1.新建springBoot项目. 2.打包生成jar 3.丢到liunex丢到(/usr/local/software) 4.检查进程,ps -ef|grep java (java代表所有的java ...
- nginx proxy_pass 指令
nginx proxy_pass 指令 文档 Nginx 官方文档 https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pa ...
- 装ubuntu的坑
装ubuntu安装盘的U盘,在BOOT中会出现两种载入方式,切记不要用UEFI方式打开,否则安装ubuntu会在最后卡在GRUB的安装上面,然后失败.
- django ORM创建
简短的例子 from django.db import models class Person(models.Model): first_name = models.CharField(max_len ...