第8章 模式匹配
Scala中的模式匹配,类似于Java中的switch语法
8.1 基本语法
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明。
match语法中没有break语句
case _ 默认值, 如果没有case _ 则会抛出异常MatchError。
注:默认值并不需要一定是case _ ,下划线只是一个通配符,下划线可以是任意的变量名,如case a
、 case abc
、case _
object Test01{
def main(args:Array[String]):Unit={
// 1 基本语法
val x:Int = 2
val y:String = x match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case _ => "other" // 默认值
}
println(y)
// 2 示例:用模式匹配实现简单的二元运算
val a = 25
val b = 13
def matchDualOp(op : Char):Int = op match {
case '+' => a + b
case '-' => a - b
case '*' => a * b
case '/' => a / b
case '%' => a % b
case _ => -1
}
println(matchDualOp('+'))
println(matchDualOp('-'))
println(matchDualOp('*'))
}
}
8.2 模式守卫
模式守卫, 通过if来进行判断
object Test01{
def main(args:Array[String]):Unit={
// 模式守卫, 通过if来进行判断
// 求绝对值
def abs(num:Int):Int={
num match{
case i if i >=0 => i
case i if i <0 => -i
}
}
}
}
8.3 模式匹配类型
模式匹配可以匹配所有的字面量,包括字符串,数组,数字,布尔值等
8.3.1 匹配常量
object Test02{
def main(args:Array[String]):Unit={
// 1 匹配常量
def describeConst(x : Any):String= x match{
case 1 => "Num One"
case "hello" => "string hello"
case true => "true"
case '+' => "Char +"
case _ => "默认值" // 没有case _ 则会抛出异常MatchError
}
}
}
8.3.2 匹配类型
泛型擦除,也就是 List[String],JVM只会判断他是一个List,并不会判断他的泛型。 如List[Int],List[Double]都会认为是List
Array类型没有泛型擦除,所以Array可以判断泛型
object Test02{
def main(args:Array[String]):Unit={
def describeType(x : Any):String = x match{
case i:Int => "Int"+i //匹配Int类型
case s:String => "String"+s //
case list:List[String] => "List"+list//List的泛型是没有用的,泛型擦除
case array:Array[Int] => "Array[Int]"+array.mkString(",") // array的泛型有用
case a => "默认值" + a //默认值并不需要用_,_只是一个通配符
}
println(describeType(List(1,2,3,4))) // List
}
}
8.3.3 匹配数组
匹配数组
object Test02{
def main(args:Array[String]):Unit={
for( arr <- List( Array(0) , Array(1,0) , Array(1,0,1), Array("hello",20) ) ){
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 _ => "默认值"
}
println(result)
}
}
}
8.3.4 匹配List
匹配列表
object Test02{
def main(args:Array[String]):Unit={
// 方式1
for (list <-List(List(0),List(1,0),List(1,0,1)){
val result = list match{
case List(0) => "只有一个元素,只能为0"
case List(x,y) => "两个元素,分别为"+x+y
case List(0, _*) => "以0开始"
case List(a) => "只有一个元素"+a
case _ => "默认值"
}
// 方式2
val list = List(1,2,3,4)
list match{
case first :: second :: rest => println(s"$first , $second , $rest")
case _ => println("默认值")
}
// 输出结果
// 1 , 2 , List(3,4)
}
}
8.3.5 匹配元组
object Test02{
def main(args:Array[String]):Unit={
for (tuple <- List ( (0,1) , (0,2) , (0,1,0), (1,"hello",1) )){
val result = tuple match{
case (a , b) => "二元组,分别是"+"("+a+","+b+")"
case (0 , _) => "第一个元素是0,并且是二元组"
case (a,b,0) => "三元组,最后一个是0"
case (x,y,z) => "三元组,分别是"+x+y+z
}
}
}
}
元组匹配的扩展
object Test03{
def main(args:Array[String]):Unit={
// 1 在变量声明时匹配
val (x,y) = (10 , "hello")
println(s" $x , $y ")
val List(first, second , _*) = List(23,15,9,78)
println(first + " " + second)
fir :: sec :: rest = List(12,34,23,75)
println(fir + " " + sec + " " + rest)
// 12 34 List(23,75)
// fir表示12 , sec表示34 , rest表示List(23,75)
// 2 for推导式中进行模式匹配
val list:List[(String,Int)] = List(("a",12),("b",35),("c",27))
// 遍历方式1
for(elem <- list){
println(elem._1 + " " + elem._2)
}
// 遍历方式2
// 将List的元素直接定义为元组,对变量赋值
for( (word,count) <- list ){
println(word + " " + count)
}
// 遍历方式3
for( (word,_) <- list ){
println(word)
}
// 可以指定某个位置的值,必须是多少
// 元组的第一个数必须是"a"
for( ("a",count) <- list){
println(count)
}
}
}
8.3.6 匹配对象及样例类
(1)定义类
(2)定义伴生对象,写apply方法和 unapply方法
object Test04{
def main(args:Array[String]):Unit={
val student = new Student("alice",18)
// 针对对象实例的内容进行匹配
val result = student match{
case Student("alice",18) => "alice,18"
case _ => "默认值"
}
}
}
// 定义类
class Student(val name:String, val age:Int)
// 定义伴生对象
object Student{
def apply(name:String,age:Int):student = new Student(name,age)
// 必须实现一个unapply方法,用来对对象属性进行拆解
def unapply(student:Student):Option[(String,Int)]={
if(student== null){
None
}else{//匹配规则
Some((student.name, student.age))
}
}
}
样例类
通过case关键字,就可以直接实现伴生对象的apply方法和unapply方法
object Test05{
def main(args:Array[String]):Unit={
val student = Student("alice",18)
// 针对对象实例的内容进行匹配
val result = student match{
case Student("alice",18) => "alice,18"
case _ => "默认值"
}
}
}
// 定义为样例类,
// 自动生成伴生对象的apply方法和unapply方法
case class Student1(name:String , age:Int)
8.4 偏函数中的模式匹配(了解)
偏函数是函数的一种。
例如该偏函数输入的类型为List[Int],而我们需要的是第一个元素是0的集合,就是通过模式匹配实现的。
偏函数的定义
val second:PartialFunction[List[Int],Option[Int]]={
case x :: y :: _ => Some(y)
}
偏函数:只处理自己感兴趣的匹配。
所以在代码中需要定义多个偏函数,完成全部功能
object Test06{
def main(args:Array[String]):Unit={
val list:List[(String,Int)] = List(("a",12),("b",20) , ("c",27))
// map转换,实现key不变,value2倍
val newList = list.map(tuple => (tuple._1 , tuple._2 * 2))
// 2 用模式匹配对元组元素赋值,实现功能
val newList2 = list.map(
tuple => {
tuple match{
case (word,count) => (word , count*2)
}
}
)
// 3 省略lambada表达式的写法,进行简化
// 即偏函数
val newList3 = list.map(
case (word,count) => (word, count *2)
)
println(newList)
println(newList2)
println(newList3)
}
}
偏函数的应用
object Test06{
def main(args:Array[String]):Unit={
// 偏函数的应用,求绝对值
// 对输入数据分为不同的情形,正、负、0
// 对于大于0的部分
val positiveAbs:PartialFunction[Int,Int] = {
case x if x > 0 => x
}
// 对于小于0的部分
val negativeAbs:PartialFunction[Int,Int] = {
case x if x < 0 => x
}
val zeroAbs:PartialFunction[Int,Int] = {
case 0 => 0
}
// 多个偏函数组成一个完整的函数,然后把x传进去
def abs(x:Int):Int = (positiveAbs orElse negativeAbs orElse zeroAbs)(x)
println(abs(-67))
println(abs(68))
}
}