// Java int i = 1; switch ( i ) { case0 : break; case1 : break; default : break; }
Scala的模式匹配
1 2 3 4 5 6 7 8 9 10 11 12 13
// 模式匹配,类似于Java的switch语法 val oper = '#' val n1 = 20 val n2 = 10 var res = 0 oper match { case '+' => res = n1 + n2 case '-' => res = n1 - n2 case '*' => res = n1 * n2 case '/' => res = n1 / n2 case _ => println("oper error") } println("res=" + res)
match的细节和注意事项
如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句
如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError
每个case中,不用break语句,自动中断case
可以在match中使用其它类型,而不仅仅是字符
=> 等价于 java swtich 的 :
=> 后面的代码块到下一个 case, 是作为一个整体执行,可以使用{} 扩起来,也可以不扩。
2. 守卫
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫
1 2 3 4 5 6 7 8 9 10 11
for (ch <- "+-3!") { var sign = 0 var digit = 0 ch match { case '+' => sign = 1 case '-' => sign = -1 // 说明.. case _ if ch.toString.equals("3") => digit = 3 case _ => sign = 2 } println("ch=" + ch + " " + "sign=" + sign + " " + "digit=" + digit)
// 类型匹配, obj 可能有如下的类型 val a = 7 val obj = if (a == 1) 1 elseif (a == 2) "2" elseif (a == 3) BigInt(3) elseif (a == 4) Map("aa" -> 1) elseif (a == 5) Map(1 -> "aa") elseif (a == 6) Array(1, 2, 3) elseif (a == 7) Array("aa", 1) elseif (a == 8) Array("aa")
//1. 根据Object的类型来匹配 // a:Int是一个变量,如果匹配到了,会把obj赋值给a val result = obj match { case a: Int => a case b: Map[String, Int] => "对象是一个字符串-数字的Map集合" case c: Map[Int, String] => "对象是一个数字-字符串的Map集合" case d: Array[String] => "对象是一个字符串数组" case e: Array[Int] => "对象是一个数字数组" case f: BigInt => Int.MaxValue case _ => "啥也不是" } println(result) //输出:啥也不是
类型匹配注意事项
Map[String, Int] 和Map[Int, String]是两种不同的类型,其它类推。
在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错.
1 2 3 4 5 6 7 8
val obj = 10 // val obj=Map("hell0"->12) val result = obj match { case a: Int => a case b: Map[String, Int] => "Map集合" case _ => "啥也不是" } //说明:编译器报错
一个说明:
1 2 3
val result = obj match { case i : Int => i }
上述代码中的 case i : Int => i表示 将 i = obj (其它类推),然后再判断类型
如果 case _ 出现在match 中间,则表示隐藏变量名,即不使用,而不是表示默认匹配,如下所示
// 类型匹配, obj 可能有如下的类型 val a = 7 val obj = if(a == 1) 1 elseif(a == 2) "2" elseif(a == 3) BigInt(3) elseif(a == 4) Map("aa" -> 1) elseif(a == 5) Map(1 -> "aa") elseif(a == 6) Array(1, 2, 3) elseif(a == 7) Array("aa", 1) elseif(a == 8) Array("aa") val result = obj match { case a : Int => a case _ : BigInt => Int.MaxValue//看这里! case b : Map[String, Int] => "对象是一个字符串-数字的Map集合" case c : Map[Int, String] => "对象是一个数字-字符串的Map集合" case d : Array[String] => "对象是一个字符串数组" case e : Array[Int] => "对象是一个数字数组" case _ => "啥也不是" } println(result)
for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1))) { val result = arr match { caseArray(0) => "0" caseArray(x, y) => x + "=" + y caseArray(0, _*) => "以0开头和数组" case _ => "什么集合都不是" } println("result = " + result) }
输出
1 2 3 4 5
result = 0 result = 1=0 result = 以0开头和数组 result = 什么集合都不是 result = 什么集合都不是
6. 匹配列表
案例
1 2 3 4 5 6 7 8 9
for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) { val result = list match { case0 :: Nil => "0"//返回只有一个0的列表 case x :: y :: Nil => x + " " + y //匹配两个元素列表 case0 :: tail => "0 ..."//以0开头,后面有任意个元素,tail表示后面有任意 case _ => "something else" } println(result) }
输出
1 2 3 4
0 1 0 0 ... something else
请思考,如果要匹配 List(88) 这样的只含有一个元素的列表,并原值返回.应该怎么写?
1 2 3 4 5 6 7 8 9
for (list <- Array(List(99), List(88), List(0, 0, 0), List(1, 0, 0))) { val result = list match { case88 :: Nil => "88"//返回只有一个88的列表 case x :: y :: Nil => x + " " + y //匹配两个元素列表 case0 :: tail => "0 ..."//以0开头,后面有任意个元素,tail表示后面有任意 case _ => "something else" } println(result) }
输出
1 2 3 4
something else 88 0 ... something else
7. 匹配元组
案例
1 2 3 4 5 6 7 8 9 10
// 元组匹配 // 元组匹配 for (pair <- Array((0, 1),(0,1,1), (1, 0), (1, 1), (1, 0, 2))) { val result = pair match { // case (0, _) => "0 ..."//匹配以0开头的二元组,但是第二个元素我舍弃,以后我不用它 case (y, 0) => y //匹配一个二元组,但是第二个元素必须是0 case _ => "other"//. } println(result) }
//给出案例表示有一捆数,单本漫画(40-10) +文学作品(两本书)(80+30-20)= 30 + 90 = 120.0 val sale = Bundle("书籍", 10, Book("漫画", 40), Bundle("文学作品", 20, Book("《阳关》", 80), Book("《围城》", 30)))
(3)知识点1-description绑定到第一个Book的描述
请思考:如何取出“漫画”
1 2 3 4 5 6
//使用case语句,得到"漫画" val res = sale match { //如果我们进行对象匹配时,不想接受某些值,则使用_ 忽略即可,_* 表示所有 caseBundle(_, _, Book(desc, _), _*) => desc } println("res="+res) //res=漫画
(4)知识点2-通过@表示法将嵌套的值绑定到变量。_*绑定剩余Item到rest
1 2 3 4 5 6 7 8 9 10
//得到一个元祖 val result2 = sale match { //@ Book(_, _)直接返回整个对象 caseBundle(_, _, art @ Book(_, _), rest @ _*) => (art, rest) }