Scala 模式匹配

Scala 模式匹配

一、模式匹配

Scala 中的模式匹配类似于Java中的switch语法,但是scala 从语法中补充了更多的功能,所以更加强大

1、基本语法

模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行相对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有的case都不匹配,那么会执行case…分支,类似于Java中的default语句

2、语法说明

(1) 如果所有case都不匹配,那么会执行case_分支,类似于Java中的default语句,若此时没有case_分支,那么会抛出 MatchError
(2) 每个case中,不需要使用break 语句,自动中断case
(3) match case 语句可以匹配任何类型,而不是字面量
(4) => 后面的代码块,直到下一个case 语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括

3、案例示例

package Scala04_moshipipei
//模式匹配基本语法
class test01_moshi {

}
object test01_moshi{
  def main(args: Array[String]): Unit = {
    //1、基本语法定义
    val x:Int = 10
    val y:String = x match {
      case 1 => "one" //如果为1那么返回的是one,中间是=> 连接
      case 2 => "two"
      case 3 => "there"
      case _ => "这就是默认情况了,0"
    }//判断x等于什么,如果x为1那么y就是one,如果x为2那么y就是two
    println(y)

    //2、示例;用模式匹配实现简单的二元运算
    val a = 25
    val b = 13
    def hanshu(op:Char) = op match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case '%' => a % b
      case _ => "非法运算符"

    }
    println(hanshu('*'))
    println(hanshu('+'))
    println("\\") //传一个字符进去,还要进行转义


  }
}

二、模式守卫

如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫
注意num 就是 那个 i,然后调用的时候传入参数进去就可以了

// 模式守卫
    //求一个整数的绝对值
    def fanfga(num:Int) = num match { //num就是下面的那个i
      case i if i >= 0 => i //定义一个i,如果i大于等于0就返回i
      case i if i < 0 => -i //如果小于0 那么输出-i,那肯定就是绝对值

    }
    println(fanfga(5))
    println(fanfga(0))
    println(fanfga(-5))

在这里插入图片描述

三、模式匹配类型

Scala 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
推荐还是把 case _ 加上,因为写的条件可能就那么几个,要是写错了,就会报 MatchError

1、匹配常量

 //Scala 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
    //1、匹配常量
    def hanshu(x:Any):String = x match { //返回值不一定非得String,其他的也可以
      case 1 => "num one" //这就是返回值
      case "hello scala" => "String hello"
      case true => "Boolen true" //连布尔类型都可以
      case '+' => "Char +"
      case _ => ""  //建议还是要设置一个这个,然后条件是有限的,传入参数要是没有就报错了
    }
    println(hanshu(1))
    println(hanshu("hello scala"))
    println(hanshu(true))
    println(hanshu(0.3))

在这里插入图片描述

2、匹配类型

Scala 不仅仅可以匹配常量,还可以匹配数据结构,比如列表,数组.
注意:类型匹配的时候要注意,比如定义了List[String]泛型,规定的定义的是String类型的,但是Int类型的还是匹配上了,因为Scala 的底层有泛型擦除,他只会匹配到是一个list,泛型会自动擦除。而数组比较特殊,它是没有泛型擦除的,所以特别注意这两个地方,容易出现Bug

package Scala04_moshipipei
//模式匹配类型
class test02_pipeileixing {

}
object test02_pipeileixing{
  def main(args: Array[String]): Unit = {
    //Scala 中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。
    //1、匹配常量
    def hanshu(x:Any):String = x match { //返回值不一定非得String,其他的也可以
      case 1 => "num one" //这就是返回值
      case "hello scala" => "String hello"
      case true => "Boolen true" //连布尔类型都可以
      case '+' => "Char +"
      case _ => ""  //建议还是要设置一个这个,然后条件是有限的,传入参数要是没有就报错了
    }
    println(hanshu(1))
    println(hanshu("hello scala"))
    println(hanshu(true))
    println(hanshu(0.3))

    println("================")
    //2、匹配类型
    def hanshu2(x:Any):String = x match {
      case i:Int => "int" + i //相当于前面规定了这个变量必须的是Int类型的才能匹配上
      case i:String => "String," + i
      case list: List[String] => "list:" + list //连List类型都可以定义
      case array:Array[Int] => "现在是第"+array.mkString(",")+"圈" //因为数组直接输出是引用,所以要用mkString方法输出
      case a => "Something else:" + a //这是兜底的方法,要拿到值的话就不能用 _ ,必要要设置一个变量
    }
    println(hanshu2(35))
    println(hanshu2("hello"))
    println(hanshu2(List("hi","hello")))
    println(hanshu2(List(2,23)))
    println(hanshu2(Array("hi","hello")))
    println(hanshu2(Array(2,23)))
  }
}

在这里插入图片描述

3、匹配数组

Scala 模式匹配,匹配数组非常强大,可以进行各种模糊的匹配,比如可以匹配必须是三个元素,或者中为1的三个元素的数组。

   //3、匹配数组
    for (arr <- List(
      Array(0),
      Array(1,0),
      Array(0,1,0),
      Array(1,1,0),
      Array(2,3,7,15),
      Array("hello",20,30)
    )){
     val result = arr match {
       case Array(0) => "0"
       case Array(1,0) => "1,0"
       case Array(x,y) => "Array:" + x + y //相当于可以进行模糊查询,匹配两元素数组
       case Array(0,_*) => "以0开头的数组"
       case Array(x,1,z) => "中间为1的三元素数组"
       case _ => "兜底的方法"
     }
      println(result)
    }

在这里插入图片描述

4、匹配列表

列表的匹配有两种方式,第一种和数组的匹配的方式是一样的,
第二种是: case first :: second :: rest => println(s"first:${first} second:${second} rest ,rest是列表,first是第一个元素,second是第二个元素,表示这个列表中至少要有两个元素才能匹配到。列表的这种匹配方式非常常用。

 //方式一
    for(list <- List(
      List(0),
      List(1,0),
      List(0,0,0),
      List(1,1,0),
      List(88),
      List("hello")
    )){
      val result2 = list match { //这个list就是前面的那个list

        case List(0) => "0"
        case List(x,y) => "List(x,y):" + x + "," + y //这个x,y就是两个数的那个列表
        case List(0,_*) => "List(0,...)" //必须以0开头的列表。后面的个数不限*是通配符
        case List(a) => "List(a)" //表示list里面只有一个元素
        case _ => "something else"
      }
      println(result2)

    }
    println("=====================")
    //方式二
    //这种方式在列表匹配里面非常常用
    val list = List(1,2,5,7,24)
    val list1 = List(24)
    list1 match {
      case first :: second :: rest => println(s"first:${first} second:${second} rest ${rest}") //相当于rest是一个列表,第一个元素是first,第二个元素是second
      case _ => println("something else")
    }

5、匹配元组

元组的匹配跟之前的列表和数组的匹配是非常相似的

  for(tuple <- List(
      (0,1),
      (0,0),
      (0,1,0),
      (1,23,56),
      ("hello",true,0.5)
    )){
      val result = tuple match {
        case (a,b) => println(s"${a},${b}") //这就是一个二元组
        case (0,_) => println("0,_") //表示第一个元素是0,第二个元素不做要求的一个二元组
        case (a,1,_) => println("a,1,_"+ a) //表示中间那个元素必须是1,最后一个元素不关心
        case _ => "something"
      }
      println(result)
    }

除此之外很有很多操作,很灵活

package Scala04_moshipipei
//元组匹配的扩展,元组的匹配是有一点特殊的,是很灵活的
class test03_MatchTuple {

}
object test03_MatchTuple{
  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) //把first赋值给了23,吧second赋值给了15
    println(s"first:${first},second:${second}")

    val fir :: se :: rest = List(23,15,9,78) //想要吧后面两个赋值给一个,那么还是::这种方法
    println(s"first:${fir},second:${se},rest:${rest}")

    //2、for推导式中进行模式匹配
    val list:List[(String,Int)] = List(("a",12),("b",35),("c",27),("a",24))
    for (i <- list){ //使用增强for循环进行遍历
      println(i._1 + " " + i._2)
    }
    //2.2 将List的元素直接定义为元组,对变量赋值
    for((word,count) <- list){
      println(word+ " " +count) //直接输出就可以了
    }
println("=============")
    //2.3 可以不考虑某个位置的变量,只遍历key或者value
    for((word,_) <- list){
      println(word) //这样就得到的全都是key了
    }
println("==================")
    //2.4 指定某个位置的值必须是多少
    for (("a",count) <- list){
      println(count) //把所有key是"a"对应的value值都打印出来
    }

  }
}

6、匹配对象及样例类

(1) 基本语法

class User(val name:String,val age:Int) 这个可以说是一个非常强大的功能,通过伴生对象里面的值来进行匹配,伴生对象里面要有apply方法,还要有unapply方法,用来对对象属性进行拆解,不然会报错。
步骤简单来说就是,首先定义一个类,然后定义它的伴生对象,然后再伴生对象里面实现apply方法,然后还要是先unapply方法

package Scala04_moshipipei

class test04_Object {

}
object test04_Object{
  def main(args: Array[String]): Unit = {
    val student = new Student("aex",18)

    //针对对象实例的内容进行匹配

    val result = student match {
      case Student("aex",18) => "aex,18"
      case _ => "else"
    }
    println(result)

  }
}

//定义类
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) //这样就拆分出来了
    }
  }


}
(2) 优化case样例类

上面那种方式,虽然实现了,但是太繁琐了违背了scala简洁的定义,所以有了样例类,样例类的定义非常简单,直接在类的前面加上case关键字
例如:case class Student1(val name:String,val age:Int){}
定义了样例类之后,就相当于自动实现了伴生类,apply方apply法和unapply方法,然后可以直接进行对象匹配了

package Scala04_moshipipei
//样例类,对象匹配的简化
class test05_yanglilei {

}
object test05_yanglilei{
  def main(args: Array[String]): Unit = {
    val student = new Student1("aex",19)

    val result = student match {
      case Student1("aex",19) => "aex,18"
      case _ => "没有可以进行匹配的"
    }
    println(result)
  }
}

//定义样例类 前面加一个case关键字就可以了
//定义了样例类,就相当于自动实现了伴生对象,apply方法和unapply方法
case class Student1(val name:String,val age:Int){

}

7、偏函数式的模式匹配(了解)

偏函数也是函数的一种,通过偏函数我们可以方便的对输入参做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是0的集合,这就是通过模式匹配实现的。
偏函数定义

package Scala04_moshipipei
//偏函数
class test06_PartialFunction {

}
object test06_PartialFunction{
  def main(args: Array[String]): Unit = {
    val list = List(("a",12),("b",35),("c",27),("a",13)) //二元组

    //1、map转换,实现key不变,value变成原来的2倍
    val newList = list.map(a => (a._1,a._2*2)) //下滑1第一个元素不变,第二个元素*2
    println(newList)

    //2、模式匹配也可以做这个操作,模式匹配对元组元素赋值,实现功能
    val newList2 = list.map(
      a => {
        a match {
          case (word,count) => (word,count*2) //直接这样就赋值了
          case _ => "没有匹配的"
        }
      }
    )
    println(newList2)
    //3、省略lambda 表达式的写法,进行简化
    val newList3 = list.map{
      case (word,count) => (word,count*2)
  }
    println(newList3)

    //偏函数的应用,求绝对值
    //对输入数据分为不同的情形:正,负,0
    val zheng:PartialFunction[Int,Int] = { //输入的类型是Int,返回的类型也是一个Int
      case x if x > 0 => x
    }
    //这是负数的偏函数
    val fushu:PartialFunction[Int,Int] = { //输入的类型是Int,返回的类型也是一个Int
      case x if x < 0 => -x
    }
    //这是为0的情况
    val zero:PartialFunction[Int,Int] = { //输入的类型是Int,返回的类型也是一个Int
      case 0 => 0
    }

    def abs(x:Int):Int = (zheng orElse fushu orElse zero ) (x) //前面是作为一个整体

    println(abs(-5))
    println(abs(0))
    println(abs(35))
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值