scala使用match关键字声明,每个分支同样使用case关键字,执行逻辑类似于java的switch,但功能更强大
数值匹配
每个分支注明具体数值,当匹配对象的数值与具体数值相等时,进入对应分支
object ModeMatch {
def main(args: Array[String]): Unit = {
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
// _代表未匹配情况,类似于java中的default分支
case _ => println("operator erro")
}
println("res=" + res)
}
}
注意事项:
- 从上到下匹配,匹配到一个就执行对应的代码块
- 不可以写break,会自动退出match
- case_相当于javaswitch中的default
- 如果什么都没有匹配上,并且没有写case_,就会抛出MatchError异常
- 可以使用多种类型
case分支可以设置条件守卫,在case分支后面增加if条件
object ModeMatch {
def main(args: Array[String]): Unit = {
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 _ if oper.equals("3") => res = n1 / n2 => res = n1 / n2
case _ => println("operator erro")
}
println("res=" + res)
}
}
类型匹配
def matchType(x: Any): Unit = x match {
case n: Long => println("Long " + n)
case n: Int => println("Int " + n)
case 1 => println(1)
case n: String => println("String " + n)
case _ => println("match failed")
}
测试:
def main(args: Array[String]): Unit = {
matchType(1)
matchType(1L)
matchType("1")
matchType('1')
}
输出结果:
Int 1
Long 1
String 1
match failed
注意事项
- 在匹配时不会自动向上转向,案例中可以看到传入一个Int类型数值,不会被前面的Long类型匹配
- Map[String,Int]和Map[Int,String]被认为是不同的类型
- 在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有就报错
集合匹配
def matchArr(arr: Array[String]): Unit = arr match {
// 匹配具有两个元素的数组,且第二个元素必须是"12"
case Array(_, "12") => print("success!!")
// 匹配具有一个元素的数组,且元素值必须是"class"
case Array("class") => println("hello kb11")
// 匹配具有两个任意元素(字符串类型)的数组
case Array(str1, str2) => println("hello " + str1 + " " + str2)
// 匹配具有任意数量各元素(至少一个,且第一个元素值为"class")的数组
case Array("class", _*) => println("hello kb12 *")
// 匹配第三个元素值为"123"且元素个数为3的数组,并且把第二个元素的值赋值给b
case Array(_, b: String, "123") => println(arr(0) + b + "123123")
case _ => println("object mismatch")
}
- 当匹配目标为
Array(0)
时,就必须使用只包含一个0元素的数组匹配 - 当匹配目标为
Array(x,y)
时,需要使用包含两个元素的数组匹配,因为设置了变量名,会将数组的变量一一赋值给变量,如果某各位置上的变量名为_
,则表示此处有数值,但不使用变量接收 - 当匹配目标为
Array(0,_*)
时,需要使用以0元素开头的数组匹配,*
表示有0或者多个元素,该标记类似于函数形参中的可变参数,只能出现一次且只能出现在最后
类似的有列表匹配:
object ModeMatch {
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 _ => "something else"
}
println(result)
}
}
}
//输出结果
/*
0
1+0
0...
something else
*/
元组匹配
object ModeMatch {
def main(args: Array[String]): Unit = {
for (list <- Array((0,1), (1, 0), (1, 1), (1, 0, 2))) {
val result = list match {
case (0,_) => "0"//匹配两个元素的,第一个是0
case (x,0) => x//匹配两个元素的,第二个是0
case _ => "something else"
}
println(result)
}
}
}
//输出结果
/*
0
1
something else
something else
*/
对象匹配
case class Teacher(name: String, age: Int)
def match3(teacher: Teacher): Unit = teacher match {
// 匹配name属性为zs,age属性37的teacher
case Teacher("zs", 37) => println("case1 matched")
// 匹配age属性20的teacher,name属性任意
case Teacher(_, 20) => println("case2 matched")
// 匹配name属性为bob的teacher
case _ if teacher.name == "bob" => println("special case matched")
case x: Teacher => println("type mismatch")
}
匹配对象过程实际会调用对象的unapply方法,如果返回Some则会匹配成功,如果返回None匹配失败
测试案例:
object Test0426 {
def main(args: Array[String]): Unit = {
val p: Person = new Person("zs", 18)
p match {
case Person("zs", age) => println("case1 matched age " + age)
case _ => println("type mismatch")
}
}
}
object Person {
val name: String = "zs"
val age: Int = 18
def apply: Person = new Person()
def apply(name: String, age: Int): Person = new Person(name, age)
def unapply(arg: Person): Option[(String, Int)] = Some((Person.name, Person.age + 20))
}
class Person(name: String, age: Int) {
def this() {
this("ls", 20)
}
}
// 输出结果:case1 matched age 38
可以看到实际输入age属性为18,输出age属性为38
将unapply方法返回值改为None后,输出结果:type mismatch
,虽然实际name属性为'zs'
,符合匹配条件,但是最终结果匹配失败
模式匹配运用
val map = Map("a" -> 1, "b" -> 2, "c" -> 0)
// 普通遍历,会输出所有键值对
for ((k, v) <- map){
println(s"k:$k v:$v")
}
// 只会匹配V值为0的键值对
for ((k, 0) <- map){
println(s"k:$k v:0")
}