scala-pattern-match-basic
模式匹配概念
对数据进行深度分解和检查的一个功能,极其强大
涉及到两个术语:
- extraction 提取
- deconstruction 解构
在后面深入分析他俩
基础语法
类比Java中的swith
选择器 match {分支们}
每个分支就是一个模式,都是以case
作为开头
我们要研究有哪些模式
模式类型
- 通配模式
- 常量模式
- 变量模式
- 构造方法模式
- 序列模式
- 元组模式
- 附带类型模式
通配模式
意思就是啥都能匹配
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相关推荐
- LPC43xx SGPIO Pattern Match Mode
模式匹配 所有位串均具有模式匹配功能. 该功能可用于检测启动代码等.要使用该功能,则必须用需匹配的模式来对REG_SS 编程 (请注意, POS 达到零时 REG_SS 不会与 REG 交换!) M ...
- G面经prepare: Pattern Match
设定一个pattern 把 'internationalization' 变成 'i18n', 比如word是house,pattern可以是h3e, 3se, 5, 1o1s1等, 给pattern ...
- scala 模式匹配 match
文章目录 一.match 基本介绍 二.match 的细节和注意事项 三.模式匹配之条件守卫 四.模式匹配之变量匹配.常量匹配 五.模式匹配之类型匹配 六.模式匹配之数组匹配 七.模式匹配之集合匹配 ...
- Scala Learn 1 Basic
Chap 0 前言 focus on: Scala 的语法十分简洁 Scala 运行在虚拟机之上, 可以使用 java 的海量类库和工具 Scala 拥抱函数式编程的同时,并没有废弃面向对象 Scal ...
- scala模式匹配match操作
为什么80%的码农都做不了架构师?>>> match 转载于:https://my.oschina.net/wii01/blog/893566
- Scala:try match
Scala:try & match try表达式 match 表达式 try表达式 try表达式的语意与java中try-catch-finally是一样的. 但是try在scala中不是一个 ...
- Spark记录-Scala程序例子(函数/List/match/option/泛型/隐式转换)
object func {def main(args:Array[String]):Unit={//函数赋值给变量时, 必须在函数后面加上空格和下划线.def sayHello(name: Strin ...
- Scala教程之:Enumeration
Enumeration应该算是程序语言里面比较通用的一个类型,在scala中也存在这样的类型, 我们看下Enumeration的定义: abstract class Enumeration (init ...
- scala中:: , +:, :+, :::, +++的区别
原文链接:https://segmentfault.com/a/1190000005083578 --------------------------------------------------- ...
- Scala的抽象语法树打印小工具-小拉达
为什么80%的码农都做不了架构师?>>> 最近做的两个项目,一个是VeriScala,另一个是Lickitung,都涉及到了Scala的抽象语法树(AST),前者是写macro ...
最新文章
- redis 内存不足 排查_排查redis占用内存达90%以上
- Spring(1)-IOC
- Android大环境杂谈待续中
- 教你webpack、react和node.js环境配置(上篇)
- CDM CDP及传统备份技术对比
- c语言关键字识别程序,c语言-以关键字搜索程序
- vs各个版本的编译器号
- Anaconda下载安装教程
- linux tar 命令安装,Linux tar 命令 command not found tar 命令详解 tar 命令未找到 tar 命令安装 - CommandNotFound ⚡️ 坑否...
- Linux下PCIE设备分析软件
- 全球著名编程大赛地址
- linux mv文件个数,关于linux:mv一个文件,其中包含Shell脚本中的空格
- Java读写gif格式图片,解决ImageIO读取gif文件只读取第一帧的问题(read and write gif format pictures in Java)
- 五步轻松搞定QGIS三维地形浏览
- MFC无边框窗体设置窗口圆角,并且绘制边框
- HDU 4379 The More The Better
- OPENGL学习(四)GLUT三维图像绘制
- 希望OL修改服务器经验,希望OL服务端架设技术教程
- Python爬取喜马拉雅有声小说【转载】
- 互联网产品经理的职责范围、能力要求