基本语法
scala的模式匹配类似于Java中的swich case语法,对一个值进行条件判断,针对不同的条件,进行不同的处理。
Scala的模式匹配除了可以对值进行匹配之外,还可以对类型、Array和List的元素情况case class、有值或没值(Option)进行匹配。
对于Spark来说,Scala的模式匹配功能也是极其重要的,在spark源码中大量地使用了模式匹配功能。因此为了更好地编写Scala程序,并且更加通畅地看懂Spark的源码,学好模式匹配都是非常重要的。
val x:Int = 2
val y:String = x match {
case 1 =>"one"
case 2 =>"two"
case 3 => "three"
case _ => "other"
}
println(y)
说明:
如果所有case都不匹配,那么会执行case _
分支,类似于Java中default
语句,
若此时没有case _
分支,那么会抛出MatchError。
每个case中,不需要使用break
语句,自动中断case。
match case
语句可以匹配任何类型,而不只是字面量。
=>
后面的代码块,直到下一个case语句之前的代码是作为一个整体执行
,可以使用{}括起来,也可以不括。
模式守卫
如果想要表达匹配摸个范围的数据,需要再模式匹配中增加条件守卫。
def abs(num:Int):Int={
num match {
//如果i>=0,返回i
case i if i >=0 => i
//如果i<0,返回-i
case i if i >0 => -i
}
模式匹配类型
常量匹配
def describeConst(x: Any): String = x match {
case 1 => "Int 1"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
case _ => ""
}
类型匹配
println(describeConst(0.1))
println(describeConst("hello")) //String hello
println(describeConst(true)) //Boolean true
类型匹配
(describeType(List("hi", "hello"))) //List List(hi, hello)
在底层操作时,会进行泛型擦除,List[String]
会被自动判定成List。
Array
不存在泛型擦除,在scala中做隐式转换之后才能调其他的方法。
def describeType(x: Any): String = x match {
case i: Int => "Int " + i
case s: String => "String " + s
case list: List[String] => "List " + list
case array: Array[Int] => "Array[Int] " + array.mkString(",")
case a => "Something else " + a //这里不使用通配符是为了获取到传入的值
}
println(describeType(7)) //Int 7
println(describeType("hello")) //String hello
println(describeType(List("hi", "hello"))) //List List(hi, hello)
println(describeType(List(2, 3))) //List List(2, 3)
println(describeType(Array("hi", "hello")))//Array[Int]
println(describeType(Array(2,23)))//Array[Int]
数组匹配
scala的匹配强大在可以进行模糊匹配。判断顺序为从上到下依次匹配,有一行匹配成功,下面的匹配代码不再执行
//3. 匹配数组
for (arr <- List(
Array(0),
Array(1, 0),
Array(0, 1, 0),
Array(1, 1, 0),
Array(2, 3, 7, 29),
Array("hello", 20, 30),
)) {
val result = arr match {
case Array(0) => "0"
case Array(1, 0) => "Array(1, 0)"
case Array(x, y) => "Array: " + x + ", " + y //匹配两元素数组
case Array(0, _*) => "以0开头的数组"
case Array(x, 1, z) => "第二个元素为1的三元素数组"
case _ => "something else"
}
println(result)
//0
//Array(1, 0)
//以0开头的数组
//第二个元素为1的三元素数组
//something else
//something else
}
列表匹配
for (list <- List(
List(0),
List(1, 0),
List(1, 1, 0),
List(0, 3, 5),
List("hello")
)){
val result = list match {
case List(0) => "0"
case List(x, y) => "List(x, y): " + x + ", " + y
case List(1, _*) => "List(1, ……)"
case List(a) => "List(a): " + a
case _ => "something else"
}
println(result)
//0
//List(x, y): 1, 0
//List(1, ……)
//something else
//List(a): hello
}
双冒号匹配
val list = List(1, 2, 5, 7, 8)
list match{
case first :: second :: rest => println(s"first: $first, second $second, rest $rest")
case _ => println("else")
}
//first: 1, second 2, rest List(5, 7, 8) 需要至少三个元素才能匹配上
元组匹配
for (tuple <- List(
(0, 1),
(0, 0),
(0, 1, 0),
(0, 1, 1),
(1, 22, 44)
)){
val result = tuple match{
case (a, b) => a + ", " + b
case (0, _) => "(0, _)"
case (a, 1, _) => "(a, 1, _) " + a
case (x, y, z) => "(x, y, z): " + x + ", " + y + ", " +z
case _ => "else"
}
println(result)
//0, 1
//0, 0
//(a, 1, _) 0
//(a, 1, _) 0
//(x, y, z): 1, 22, 44
}
元组在变量声明时匹配
val (x, y) = (10, "hello")
println(s"x: $x, y: $y") //x: 10, y: hello
val List(first, second, _*) = List(23, 1, 3, 56)
println(s"first: $first, second: $second")
//first: 23, second: 1
val fir :: sec :: rest = List(1, 2, 3, 4, 6)
println(s"first: $fir, second: $sec, rest: $rest")
//first: 1, second: 2, rest: List(3, 4, 6)
for推导式中进行模式匹配
val list1: List[(String, Int)] = List(("a", 12), ("b", 13), ("c", 34), ("a", 34))
//将list的元素直接定义为元组,对变量赋值
for ((word, count) <- list1) println(word + ", " + count)
//不考虑某个位置的变量,只遍历key或者value
for ((word, _) <- list1) println(word)
//指定某个位置的值
for (("a", count) <- list1) println(count) //12 34
对象匹配
对象匹配针对对象实例的内容进行匹配。
在模式匹配中直接新建对象实例并不符合模式匹配的语法规则,因此用伴生对象的apply方法去获取属性和方法。
object test_MatchObject {
def main(args: Array[String]): Unit = {
val student = new Student("alice", 8)
val result = student match{
case Student("alice", 8) => "alice, 8"
case _ => "else"
}
println(result) //alice, 8 匹配成功
}
}
//定义类
class Student(val name: String, val age: Int)
object Student {
def apply(name: String, age: Int) = new Student(name, age)
def unapply(student: Student): Option[(String, Int)] = {
if (student == null){
None
} else{
Some((student.name, student.age))
}
}
}