match介绍
Scala中的模式匹配类似于Java中的switch语法,但是更加强大。
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句。
应用案例
val category: String = "vip"
category match {
case "vip" => println("会员")
case "sVip" => println("超级会员")
case "normal" => println("普通会员")
case "customer" => println("普通用户")
case _ => println("游客访问")
// 下一行和上一行是相同的情况,所以永远都不会执行到
case _ => println("游客访问....第二行")
}
## 输出
会员
注意事项
- 如果所有case都不匹配,那么执行case _ 分支,类似于Java中default语句
- 如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError
- 每个case中,不用break语句,自动中断case
- 可以在match中使用其它类型,而不仅仅是字符,可以是表达式
- => 类似于 java swtich 的 :
- => 后面的代码块到下一个case, 是作为一个整体执行,可以使用{} 括起来,也可以不括。
- case可以出现多个相同的分类,但是第一个出现的情形可能被执行到,之后出现的相同情形都不会被执行到
守卫案例
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫
for (ch <- "+-*/%.") {
ch match {
case '+' => println("case+: 加法运算")
case '-' => println("case-: 减法运算")
case '*' => println("case*: 乘法运算")
case '/' => println("case/: 除法运算")
case '%' => println("case%: 求余运算")
case _ => println("case_:不支持的运算符")
}
}
## 输出
case+: 加法运算
case-: 减法运算
case*: 乘法运算
case/: 除法运算
case%: 求余运算
case_:不支持的运算符
match中的变量
如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量
for (name <- List("+", "关晓彤", "其他")) {
name match {
case "+" => println("case +: 某个固定字符")
case name => println("case name: 嗨:" + name)
case _ => println("case _: 默认输出")
}
}
## 输出
case +: 某个固定字符
case name: 嗨:关晓彤
case name: 嗨:其他
匹配类型
可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf方法
## 注意事项
1.Map[String, Int] 和Map[String, String]是两种不同的类型,严格按照泛型推断。2.在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错.
3.可以将obj赋值给对应的变量
4.如果case _:(类型),则表示要隐藏变量名,因为不需要使用变量名,不是表示默认匹配
def testType(obj: Any): Unit = {
val result = obj match {
case a: String => println("case String: 是一个字符串")
case b: Int => {
println("case Int: 是一个数字")
b
}
case _: BigInt => {
println("case BigInt: 只需要知道类型就行了,不需要使用该变量值")
Int.MaxValue
}
// c和d是两种不同的类型
case c: Map[String, Int] => {
println("case map: 是一个字符串-数字的map集合")
c
}
case d: Map[String, String] => {
println("case map: 是一个字符串-字符串的map集合")
d
}
case e: Array[Int] => println("case array: 是一个数字数组")
case f: Array[String] => println("case array: 是一个字符串数组")
case g: Boolean => println("case Boolean: 是一个布尔类型数据")
case _ => println("case _: 默认值")
}
println("输出的结果(其实也就是入参):" + result)
println()
}
def main(args: Array[String]): Unit = {
testType()
testType(Map(("AA" -> "aa")))
testType(Map(("AA" -> 13)))
testType(13)
testType(BigInt(12))
}
## 输出
case _: 默认值
输出的结果(其实也就是入参):()
case map: 是一个字符串-数字的map集合
输出的结果(其实也就是入参):Map(AA -> aa)
case map: 是一个字符串-数字的map集合
输出的结果(其实也就是入参):Map(AA -> 13)
case Int: 是一个数字
输出的结果(其实也就是入参):13
case BigInt: 只需要知道类型就行了,不需要使用该变量值
输出的结果(其实也就是入参):2147483647
匹配数组
- Array(0) 匹配只有一个元素且为0的数组。
- Array(x,y) 匹配数组有两个元素
- Array(Int) 匹配数组是数字数组
- Array(0,_*) 匹配数组以0开始
PS: 如果多个匹配都满足,会执行第一个满足的情形
for (arr <- Array(Array(0), Array(1, 0), Array(0, 1), Array(0, 1, 0), Array("abc", 1, 0, 1))) {
val result = arr match {
case Array(0) => {
println("case Array(0): 匹配只有一个元素且为0的数组")
arr
}
case Array(x, y) => {
println("case Array(x,y): 匹配有两个元素的数组")
arr
}
case Array(0, _*) => {
println("case Array(0, _*): 匹配以0元素开始的数组")
arr
}
case _: Array[Int] => {
println("case Array[Int] : 匹配数字数组")
arr
}
case _ => {
println("case _ : 默认匹配")
arr
}
}
print("数组打印:")
result.foreach(x => print(x + ", "))
println()
println()
}
## 输出
case Array(0): 匹配只有一个元素且为0的数组
数组打印:0,
case Array(x,y): 匹配有两个元素的数组
数组打印:1, 0,
case Array(x,y): 匹配有两个元素的数组
数组打印:0, 1,
case Array(0, _*): 匹配以0元素开始的数组
数组打印:0, 1, 0,
case _ : 默认匹配
数组打印:abc, 1, 0, 1,
匹配列表
for (list <- Array(List(0), List(3), List(1, 0), List(0, 0, 1), List(0, 0, 2))) {
val result = list match {
case 0 :: Nil => {
println("case List(0): 匹配元素只有0的列表")
list
}
case x :: Nil => {
println("case List(x): 匹配元素只有x的列表")
list
}
case x :: y :: Nil => {
println("case List(x,y): 匹配有两个元素的列表")
list
}
case 0 :: tail => {
println("case List(0,***): 匹配第一个元素是0的列表")
list
}
case _ => {
println("case _: 匹配默认值")
list
}
}
println(result)
## 输出
case List(0): 匹配元素只有0的列表
List(0)
case List(x): 匹配元素只有x的列表
List(3)
case List(x,y): 匹配有两个元素的列表
List(1, 0)
case List(0,***): 匹配第一个元素是0的列表
List(0, 0, 1)
case List(0,***): 匹配第一个元素是0的列表
List(0, 0, 2)
匹配元组
for (tuple <- Array(Tuple1(0), (0, 1), (13, 30), (0, 2, 1), (0, 1, 2, 3))) {
val result = tuple match {
case (0, _) => {
println("case Tuple(0,*): 匹配以0作为首位的两位元组")
tuple
}
case Tuple1(x) => {
println("case Tuple(x): 匹配值有一个元素的元组")
tuple
}
case (_, _, 1) => {
println("case Tuple(*,*,1): 匹配以1结尾的三位元组")
tuple
}
case (x, y) => {
println("case Tuple(x,y): 匹配两位元组,将原元组元素互换位置")
(y, x)
}
case _ => {
println("case _: 匹配默认值")
tuple
}
}
println(result)
## 输出
case Tuple(x): 匹配值有一个元素的元组
(0)
case Tuple(0,*): 匹配以0作为首位的两位元组
(0,1)
case Tuple(x,y): 匹配两位元组,将原元组元素互换位置
(30,13)
case Tuple(*,*,1): 匹配以1结尾的三位元组
(0,2,1)
case _: 匹配默认值
(0,1,2,3)
匹配对象
匹配规则:
- 对象必须实现对象提取器方法对象在case关键字后,会默认的调用该方法
- case后面对象参数是一个的时候实现unapply方法,
- case后面对象参数是多个的时候实现unapplySeq方法
- 如果返回Some集合视为成功
- 返回none集合视为失败
object Start {
//在case后会默认调用该方法
def unapply(d: String): Option[String] = {
if (d.contains(",")) None else Some(d)
}
//在创建对象的时候会调用该方法
def apply(d: String): String = s"hello ,$d !"
}
object StartList {
//在case后会默认调用该方法
def unapplySeq(s: String): Option[Seq[String]] = {
if (s.contains(",")) Some(s.split(",")) else None
}
//在创建对象的时候会调用该方法
def apply(d: String): String = s"hello ,$d !"
}
def testObj(): Unit = {
for (name <- Array("关晓彤", "关晓彤,沈腾,贾玲", "关晓彤,沈腾,贾玲,华晨宇")) {
val result = name match {
//case中的对象会默认调用对象中的unapply方法,返回Some集合则匹配成功,返回none就是失败
case Start(n) => {
println("case Start(n): " + n)
n
}
case StartList(first, middle, last) => {
println(s"case StartList(first, middle, last): $first,$middle,$last")
List(first, middle, last)
}
case _ => {
println("case _ : 匹配默认值")
}
}
println(s"result: $result")
}
}
def main(args: Array[String]): Unit = {
testObj()
}
## 输出
case Start(n): 关晓彤
result: 关晓彤
case StartList(first, middle, last): 关晓彤,沈腾,贾玲
result: List(关晓彤, 沈腾, 贾玲)
case _ : 匹配默认值
result: ()
变量声明中的模式
val (x, y) = (1, 2)
println("x = " + x)
println("y = " + y)
val (q, r) = BigInt(10) /% 3 // 包含了2个连续的运算符
println("10除3的商:q = " + q)
println("10除3的余:r = " + r)
val arr = Array(1, 7, 2, 9)
val Array(first, second, _*) = arr
println("first: " + first + " ; second: " + second)
## 输出
x = 1
y = 2
10除3的商:q = 3
10除3的余:r = 1
first: 1 ; second: 7