模式匹配概念

对数据进行深度分解和检查的一个功能,极其强大

涉及到两个术语:

  • extraction 提取
  • deconstruction 解构

在后面深入分析他俩

基础语法

类比Java中的swith

选择器 match {分支们}

每个分支就是一个模式,都是以case作为开头

我们要研究有哪些模式

模式类型

  1. 通配模式
  2. 常量模式
  3. 变量模式
  4. 构造方法模式
  5. 序列模式
  6. 元组模式
  7. 附带类型模式

通配模式

意思就是啥都能匹配

def myMatch(x:Any) = x match {case _ => println("通配")
}

对于这个方法,我们传入任何数据都能匹配到_ ,_是通配模式的符号。

myMatch(1)
myMatch("love")

这个模式选项一般放在最后,用来匹配其它选项

常量模式

所谓常量模式就是某个固定值直接匹配

def myMatch(x:Any) = x match {case 1 => println("数字1")case _ => println("其它")
}

变量模式

变量模式和通配有点相似,但是变量模式能完成数据的绑定,通配模式是不具有这个功能的

def myMatch(x:Any) = x match {case 1 => println("数字1")// v 是一个变量,并且绑定了值case v => println(v)
}

关于常量还是变量的问题有一些隐晦的知识稍微了解下

观察下面的代码

val number = 1def myMatch(x:Any) = x match {case  number => println("数字1")// v 是一个变量,并且绑定了值case v => println(v)
}

看上去number就是1,应该是常量,但是实际上,Scala处理的时候将它视为了变量模式,和下面的v是一样的。

val Number = 1def myMatch(x:Any) = x match {case  Number => println("数字1")// v 是一个变量,并且绑定了值case v => println(v)
}

上面的number首字母大写,scala处理的时候会去寻找该变量的真实值,将其视为常量,所以Scala用大小写区分了常量和变量模式。

另外还有集中情况也视为常量

import Math.PI
def myMatch(x:Any) = x match {case  PI => println("圆周率")// v 是一个变量,并且绑定了值case v => println(v)
}

这是从其它地方导入的值,放在这里也会视为常量

比如下面的写法也视为常量

object Demo:val girlName = "迪丽热巴"
end Demo
import Math.PI
def myMatch(x:Any) = x match {case  PI => println("圆周率")// 常量模式case Demo.girlName => println("漂亮不")case v => println(v)
}

某个类的实例引用其数据,也视为常量

class Girl(val name:String):
end Girl
val g = Girl("fbb")
def myMatch(x:Any) = x match {// 这也是常量case g.name => println("范冰冰")case v => println(v)
}

还有一种情况,可以把普通变量转为常量模式,借助反单引号也可以完成这个工作

val name = "fbb"
def myMatch(x:Any) = x match {case `name` => println("范冰冰")case v => println(v)
}

注意一点,scala区分的核心是写法,并非真实值

import Math.PIval pi = PI
def myMatch(x:Any) = x match {case pi => println("圆周率???")case v => println(v)
}

这里使用了变量接收了PI,在case后使用了pi,此时其实它是变量模式

myMatch("fbb")
myMatch(Math.PI)

这里的测试都会进入pi case,因为Scala是按照形式来的,不是按照真实值来的。

小结

  • 导入的大小常量
  • 类级别实例持有数据
  • 反单引号包裹的变量
  • 大写开头的变量

上述几种情况都会视为常量模式

构造方法模式

case class Girl(val name:String,val age:Int):def this(name:String) = this(name,18)
end Girl
def myMatch(x:Any) = x match {case Girl(a,b) => println(s"$a,$b")case v => println(s"other $v")
}

Girl这里就是一种构造方法模式,

模式匹配能够解构任意深度,你还可以指定构造中某个数据必须是某个值,比如

def myMatch(x:Any) = x match {case Girl(a,18) => println(s"$a, 真18")case Girl(a,b) => println(s"$a,$b")case v => println(s"other $v")
}

第一个case会匹配到构造出Girl的,并且age必须为18,第二个就没有18的要求,对于更细化的case应该写在前面,否则无法匹配到。

序列模式

主要是List 这样的数据可以进行匹配

def myMatch(x:Any) = x match {case List(1,3,_) => println("1,3开头 共三个元素的列表")case v => println(s"other $v")
}
myMatch(List(1,3,2))
myMatch(List(1,3,4,5,6))

第一个match是三个元素而且1,3开头符合,第二个List长度不满足,所以只能匹配到v。

如果你想确定某几个元素,长度不限制需要使用_*写法,并且要在最后

def myMatch(x:Any) = x match {case List(1,_,3,_*) => println("1 中间随意,然后3,其余多少个元素无所谓")case v => println(s"other $v")
}
myMatch(List(1,3,3)) // 能匹配
myMatch(List(1,2,3,5,6)) // 能匹配
myMatch(List(3,5,6))// 第一个数据就不符合,无法匹配

元组模式

针对Tuple

def myMatch(x:Any) = x match {case (1,"love",_) => println("1111")case v => println(s"other $v")
}
myMatch((1,"love","haha")) // 能匹配
myMatch((2,"love","haha"))

元组中不要使用_*这样的写法,因为元组本身有长度限制和_*就不搭。

附加类型模式

对数据用数据类型描述,也可以匹配

def myMatch(x:Any) = x match {case a:String => println("字符串")case v => println(s"other $v")
}

有了类型,可以做更多的事情

def myMatch(x:Any) = x match {case a:String => println(a.length)case v => println(s"other $v")
}

这里a明确是String,所以可以使用length,a和x虽然是一个东西,由于类型描述不一样,你无法使用x.length,这一点要注意下

模式守卫

模式守卫就是在某个匹配模式后可以加入一些逻辑控制

def myMatch(x:Any) = x match {case a:String if a.length > 2  => println(s"$a 够长")case v => println(s"other $v")
}
myMatch("开心")// 长度不满足,匹配v
myMatch("开心吗") // 长度满足,匹配 a
myMatch((1,"love","haha"))

变量绑定

变量绑定是在某个模式中,将某个数据再次绑定到某个变量中,需要使用@符号,我们看一个案例

def myMatch(x:Any) = x match {case Girl(name, a  @ age) => println(a)case v => println(s"other $v")
}

这里的a绑定了后面的age,这个案例非常简单,以至于看不出它有啥用。

case class Girl(val name:String,val age:Int,val boyFriend: BoyFriend):
end Girlcase class BoyFriend(val name:String , val balance:Double):
end BoyFriend
def myMatch(x:Any) = x match {case Girl(name, age, b @ BoyFriend(_,_)) => println(b.name + b.balance)case v => println(s"other $v")
}

用这种模式不用在乎里面是什么数据,并且还能完成数据的引用,如果不用这种方式,像下面这样,我们想得到BoyFriend里面的数据怎么弄?

def myMatch(x:Any) = x match {case Girl(name, age, BoyFriend(_,_)) => println()case v => println(s"other $v")
}

还有一细致的点,在Scala编程中有一个案例,我们引用说明

abstract class Expr
case class Number(number: Double) extends Expr
case class Unop(oprator:String,arg:Expr) extends Expr
def myMatch(x:Any) = x match {case Unop("abs",e @ Unop("abs",_)) => ecase _ =>
}
val r1 = myMatch(Unop("abs",Unop("abs",Number(3.3)))
)println(r1)

打印

Unop(abs,Number(3.3))

这里的含义是,对一个数连续进行两个绝对值,这样写之后可以简化为只求一次绝对值

Unop("abs",Unop("abs",Number(3.3)))

本身可以简化为 Unop(“abs”,_) 而_部分又可以视为Unop("abs",_),这部分本身赋值给变量e了,所以后续的操作直接使用e本身做abs操作即可,不用走两次。

这段逻辑有点绕,需要一定的理解能力。

我们写一段伪代码来描述其逻辑,如果不是模式匹配,原始代码

val x = Unop("abs",Unop("abs",Number(3.3)))

进行求值的之后要

(x.arg.arg x.arg.operator) x.operator

经过模式匹配后由于直接得到了e,就是一个

Unop("abs", _)

所以如果利用它计算的话,就是属于

x.arg x.operator

我这里提供一个改写的可实验论证的代码,证明这一点

object Main {def main(args: Array[String]): Unit = {val x = Unop("abs",Unop("abs",Number(3.3)))// 这里要计算两次val v = x.cal();println(v)println("==============")val x2 = myMatch(x)val x3 = x2.asInstanceOf[Unop]// 这里只需要计算一次val v2 = x3.cal()println(v2)}def myMatch(x: Any):Any = x match {case Unop("abs", e @ Unop("abs", _)) => ecase _ => None}}abstract class Expr:def cal():Any
end Exprcase class Number(number: Double) extends Expr:override def cal(): Any = number
end Numbercase class Unop(oprator: String, arg: Expr) extends Expr:override def cal(): Any = oprator match {case "abs" => {println("计算绝对值")arg.cal()}case _ => None}
end Unop

元组增强功能

scala3对元组进行了增强,使其更像列表,但是保留了每个元素的类型,*:是一个符号,用于连接数据

val heros = Seq(("傲之追猎者","雷恩加尔","狮子狗"),("傲之追猎者","雷恩加尔","狮子狗","今晚猎个痛快"),("海洋之灾","普朗克","船长"),("武器大师","贾科斯","一灯"),
)val result = heros.map{case "傲之追猎者" *: second *: third *:EmptyTuple => s"$third"case first *: other => s"$first : $other"
}
println(result)

结果

List(狮子狗, 傲之追猎者 : (雷恩加尔,狮子狗,今晚猎个痛快), 海洋之灾 : (普朗克,船长), 武器大师 : (贾科斯,一灯))

其中的EmptyTuple描述后面是空,所以第一个case就是三个元素限定死。

scala-pattern-match-basic相关推荐

  1. LPC43xx SGPIO Pattern Match Mode

    模式匹配 所有位串均具有模式匹配功能. 该功能可用于检测启动代码等.要使用该功能,则必须用需匹配的模式来对REG_SS 编程 (请注意, POS 达到零时 REG_SS 不会与 REG  交换!) M ...

  2. G面经prepare: Pattern Match

    设定一个pattern 把 'internationalization' 变成 'i18n', 比如word是house,pattern可以是h3e, 3se, 5, 1o1s1等, 给pattern ...

  3. scala 模式匹配 match

    文章目录 一.match 基本介绍 二.match 的细节和注意事项 三.模式匹配之条件守卫 四.模式匹配之变量匹配.常量匹配 五.模式匹配之类型匹配 六.模式匹配之数组匹配 七.模式匹配之集合匹配 ...

  4. Scala Learn 1 Basic

    Chap 0 前言 focus on: Scala 的语法十分简洁 Scala 运行在虚拟机之上, 可以使用 java 的海量类库和工具 Scala 拥抱函数式编程的同时,并没有废弃面向对象 Scal ...

  5. scala模式匹配match操作

    为什么80%的码农都做不了架构师?>>>    match 转载于:https://my.oschina.net/wii01/blog/893566

  6. Scala:try match

    Scala:try & match try表达式 match 表达式 try表达式 try表达式的语意与java中try-catch-finally是一样的. 但是try在scala中不是一个 ...

  7. Spark记录-Scala程序例子(函数/List/match/option/泛型/隐式转换)

    object func {def main(args:Array[String]):Unit={//函数赋值给变量时, 必须在函数后面加上空格和下划线.def sayHello(name: Strin ...

  8. Scala教程之:Enumeration

    Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enumeration的定义: abstract class Enumeration (init ...

  9. scala中:: , +:, :+, :::, +++的区别

    原文链接:https://segmentfault.com/a/1190000005083578 --------------------------------------------------- ...

  10. Scala的抽象语法树打印小工具-小拉达

    为什么80%的码农都做不了架构师?>>>    最近做的两个项目,一个是VeriScala,另一个是Lickitung,都涉及到了Scala的抽象语法树(AST),前者是写macro ...

最新文章

  1. redis 内存不足 排查_排查redis占用内存达90%以上
  2. Spring(1)-IOC
  3. Android大环境杂谈待续中
  4. 教你webpack、react和node.js环境配置(上篇)
  5. CDM CDP及传统备份技术对比
  6. c语言关键字识别程序,c语言-以关键字搜索程序
  7. vs各个版本的编译器号
  8. Anaconda下载安装教程
  9. linux tar 命令安装,Linux tar 命令 command not found tar 命令详解 tar 命令未找到 tar 命令安装 - CommandNotFound ⚡️ 坑否...
  10. Linux下PCIE设备分析软件
  11. 全球著名编程大赛地址
  12. linux mv文件个数,关于linux:mv一个文件,其中包含Shell脚本中的空格
  13. Java读写gif格式图片,解决ImageIO读取gif文件只读取第一帧的问题(read and write gif format pictures in Java)
  14. 五步轻松搞定QGIS三维地形浏览
  15. MFC无边框窗体设置窗口圆角,并且绘制边框
  16. HDU 4379 The More The Better
  17. OPENGL学习(四)GLUT三维图像绘制
  18. 希望OL修改服务器经验,希望OL服务端架设技术教程
  19. Python爬取喜马拉雅有声小说【转载】
  20. 互联网产品经理的职责范围、能力要求

热门文章

  1. 软子空间聚类_不平衡数据的软子空间聚类算法
  2. form表单的属性方法
  3. JAVA创建数组,储存学生成绩
  4. 洛谷P1263 || 巴蜀2311 宫廷守卫
  5. 零基础搭建属于自己的网站--网页设计【学习笔记8】
  6. Android-使用Android Studio实现第三方QQ登录
  7. hisi pqtool 问题汇总
  8. html计时器重置,Javascript重置倒计时
  9. 【猫优壁纸】云开发的壁纸类运营小程序、多端适配、创作者系统可运营
  10. java计算机毕业设计基于安卓Android微信小程序的应急求救信息发布系统小程序uniAPP