scala(八):模式匹配

目录

模式匹配

基本语法

模式守卫

模式匹配类型

变量声明中的模式匹配

for表达式中的模式匹配

偏函数中的模式匹配


模式匹配

Scala中的模式匹配类似于Java中的switch语法。

基本语法

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

注:

(1)如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句,若此时没有case _ 分支,那么会抛出MatchError。

(2)每个case中,不需要使用break语句,自动中断case。

(3)match case语句可以匹配任何类型,而不只是字面量。

(4)=> 后面的代码块直到下一个case语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。

案例:

object MatchTest01 {
  def main(args: Array[String]): Unit = {
    var a : Int = 5
    var b : Int = 10
    def value(oper : Char) : Int = oper match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case _ => 0
    }
    println(value('+'))
    println(value('-'))
    println(value('='))


    var oper2 : Char = '+'
    var value2 = oper2 match {
      case '+' => a + b
      case '-' => a - b
      case '*' => a * b
      case '/' => a / b
      case _ => 0
    }
    println(value2)
  }
}

 

模式守卫

如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。

案例:

object MatchTest02 {
  def main(args: Array[String]): Unit = {
    def MatchCase(x : Int) = x match {
      case i : Int if i >= 0 => i
      case j : Int if j < 0 => j
      case _ => "type ill"
    }
    println(MatchCase(4))
    println(MatchCase(-2))
  }
}

模式匹配类型

 匹配常量

scala中模式匹配可以匹配所有字面量,包括字符串、字符、数字、布尔值等等。

object MatchTest03 {
  def main(args: Array[String]): Unit = {
    println(constant(2))
    println(constant("2"))
    println(constant("hello"))
  }

  def constant(x : Any) = x match {
    case 2 => "Int two"
    case true => "Boolean true"
    case "hello" => "String is hello"
    case _ => "char is ill"
  }
}

匹配类型 

需要进行类型判断时,可以使用前文所学的isInstanceOf[T]asInstanceOf[T],也可使用模式匹配实现同样的功能。

object MatchTest04 {
  def main(args: Array[String]): Unit = {
    println(constant01(8))
    println(constant01("abc"))
    println(constant01(List(1,2,3,4)))
    println(constant01(Array("abc","bcd")))
    println(constant01(1,2,3,4,5))
  }

  def constant01(x : Any) = x match {
    case i : Int => "Int"
    case l : List[_] => "List"
    case s : String => "String"
    case a : Array[_] => "Array"
    case other => "other type" + other
  }
}

匹配数组 

scala模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素为0的数组。

object MatchTest05 {
  def main(args: Array[String]): Unit = {
    for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0),
      Array(1, 1, 0), Array(1, 1, 1, 0), Array("abc", 20))) {
      //对一个数组集合进行遍历
      println("==============")

      val str = arr match {
        case Array(0) => "0" //匹配Array(0)数组
        case Array(x, y) => x + "," + y //匹配二维数组
        case Array(0, _*) => "0开头的数组" //匹配0开头的数组
        case Array(x, y, z, n) => x + "," + y + "," + z + "," + n //匹配4维数组
        case _ => "other"
      }
      println(str)
    }
  }
}

匹配列表

object MatchTest06 {
  def main(args: Array[String]): Unit = {
    for (arr <- Array(List(0), List(1, 0), List(0, 1, 0),
      List(1, 1, 0), List(1, 1, 1, 0), List("abc", 20),
      List(66))) {
      //arr是一个存放list集合的数组
      val str = arr match {
        case List(0) => "0"
        case List(xx) => xx
        case List(x, y) => x + "," + y
        case List(0, _*) => "0 ……"
        case _ => "other"
      }
      println(str)
    }
  }
}

匹配元组

object MatchTest07 {
  def main(args: Array[String]): Unit = {
    for (arr <- Array((1),(1,0),(1,1,1),(0,1,1),(1,0,1,0))) {
      //arr是一个存放list集合的数组
      val str = arr match {
        case (1) => "1"
        case (x, 0) => x + "," + "0"
        case (0, _) => "0 ……"
        case (x,y,z) => x + "," + y + "," + z
        case _ => "other"
      }
      println(str)
    }
  }
}

匹配对象及样例类

(1)基本语法

//定义类
class Person (val name : String,val  age : Int)

//定义伴生对象
object Person {
  def apply(name: String,age: Int): Person = new Person(name,age)

  //必须实现一个unapply方法,用来对对象属性进行拆解
  def unapply(arg: Person): Option[(String, Int)] = {
    if (arg == null) {
      None
    } else {
      Some(arg.name,arg.age)
    }
  }
}

object MatchTest08 {
  def main(args: Array[String]): Unit = {
    val person: Person = Person("jeffry", 20)
    //针对对象实例的内容进行匹配
    val str = person match {
      case Person("jeffry", 20) => "yes"
      case _ => "no"
    }
    println(str)
  }
}

 

解释:

1)val person = Person("jeffry",20),该语句在执行时,实际调用的是person伴生对象中的 apply方法,因此不用new关键字就能构造出相应的对象。

2)当将Person("jeffry",20)写在case后时[case Person("jeffry",20) => "yes"],会默认调用unapply方法(对象提取器),person作为unapply方法的参数,unapply方法将person对象的name和age属性提取出来,与Person("jeffry",20)中的属性值进行匹配

3)case中对象的unapply方法(提取器)返回Some,且所有属性均一致,才算匹配成功, 属性不一致,或返回None,则匹配失败。

4)若只提取对象的一个属性,则提取器为unapply(obj:Obj):Option[T]

5)若提取对象的多个属性,则提取器为unapply(obj:Obj):Option[(T1,T2,T3…)]

6)若提取对象的可变个属性,则提取器为unapplySeq(obj:Obj):Option[Seq[T]]

(2)样例类

语法:

case class Person (name: String, age: Int)

说明:

1)样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply、toString、equals、hashCode和copy。

2)样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。

3)构造器中的每一个参数都成为val,除非它被显式地声明为var。

case class Person (val name : String,val  age : Int)

object MatchTest08 {
  def main(args: Array[String]): Unit = {
    val person: Person = Person("jeffry", 20)
    //针对对象实例的内容进行匹配
    val str = person match {
      case Person("jeffry", 20) => "yes"
      case _ => "no"
    }
    println(str)
  }
}

变量声明中的模式匹配

case class Person(name: String, age: Int)

object MatchTest010 {
  def main(args: Array[String]): Unit = {
    val (x, y) = (1, 2)
    println(s"x=$x,y=$y")
    
    val Array(first, second, _*) = Array(1, 7, 2, 9)
    println(s"first=$first,second=$second")
    
    val Person(name, age) = Person("jeffry", 22)
    println(s"name=$name,age=$age")
  }
}

 

for表达式中的模式匹配

object MatchTest11 {
  def main(args: Array[String]): Unit = {
    val map = Map("A" -> 1, "B" -> 2, "C" -> 3)
    for ((k, v) <- map) {
      //直接将map中的k-v遍历出来
      println(k + " -> " + v) //3 个
    }
    println("============")
    //遍历value=2的k-v,如果v不是2,过滤
    for ((k, 2) <- map) {
      println(k + " --> " + 2) // B->2
    }
    println("==============")
    //if v == 0 是一个过滤的条件
    for ((k, v) <- map if v >= 1) {
      println(k + " ---> " + v) // A->1 和 c->3
    }
  }
}

偏函数中的模式匹配

 定义:

val second: PartialFunction[List[Int], Option[Int]] = {

case x :: y :: _ => Some(y)

}

注:该偏函数的功能是返回输入的List集合的第二个元素。

上述代码会被scala编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为Boolean。

val second = new PartialFunction[List[Int], Option[Int]] {

//检查输入参数是否合格

override def isDefinedAt(list: List[Int]): Boolean = list match

{

case x :: y :: _ => true

case _ => false

}

//执行函数逻辑

override def apply(list: List[Int]): Option[Int] = list match

{

case x :: y :: _ => Some(y)

}

}

偏函数使用

偏函数不能像second(List(1,2,3))这样直接使用,因为这样会直接调用apply方法,而应该调用applyOrElse方法,如下

second.applyOrElse(List(1,2,3), (_: List[Int]) => None)

applyOrElse方法的逻辑为if (ifDefinedAt(list)) apply(list) else default。如果输入参数满足条件,即 isDefinedAt返回true,则执行apply方法,否则执行defalut方法,default方法为参数不满足要求的处理逻辑。

object MatchTest12 {
  def main(args: Array[String]): Unit = {
    //将该List(1,2,3,4,5,6,"test")中的Int类型的元素加一,并去掉字符串
    val list = List(1,2,3,4,5,6,"hello")
    //方法一
    val list1 = list.map {
      a =>
        a match {
          case i: Int => i + 1
          case s: String =>s + 1
        }
    }
    println(list1.filter(a=>a.isInstanceOf[Int]))
    println("===============")
    //方法二
    list.filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int] + 1).foreach(println)
    println("===============")
    //方法三
    list.collect{case x : Int => x + 1}.foreach(println)
  }
}

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值