Scala 中的模式匹配类似于 Java 中的 switch 语法
基本语法
模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需 要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹 配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支, 类似于 Java 中 default 语句。
//基本语法
val x : Int = 10
val y : String = x match {
case 1 => "一"
case 2 => "二"
case 3 => "三"
case 4 => "四"
case _ => "其他" //未满足以上则返回默认值
}
println(y)
//用法示例: 用模式匹配实现简单二元运算
val a = 25
val b = 20
def matchTow(op : Char) = op match {
case '+' => a+b
case '-' => a-b
case '*' => a*b
case '/' => a/b
case _ => -1
}
println(matchTow('+'))
- 如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句, 若此时没有 case _ 分支,那么会抛出 MatchError
- 每个 case 中,不需要使用 break 语句,自动中断 case。
- match case 语句可以匹配任何类型,而不只是字面量。
- => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以 使用{}括起来,也可以不括。
模式守卫
如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。
//模式守卫
//求整数绝对值
def abs (a :Int): Int ={
a match {
case i if i >= 0 => i
case i if i < 0 => -i
}
}
println(abs(-5))
匹配类型
需要进行类型判断时,可以使用前文所学的 isInstanceOf[T]和 asInstanceOf[T],也可使 用模式匹配实现同样的功能。
匹配常量
//匹配常量
def des(x : Any): String ={
x match {
case 1 => "one"
case "hello" => "hello scala"
case true => "yes"
case '=' => "=="
case _ => "null"
}
}
println(des("hello"))
println(des(0.3))
匹配类型
//匹配类型
def des(a: Any): String = {
a match {
case i: Int => "Int "+i
case i: String => "String "+i
case i: List[String] => "List "+i
case i: Array[Int] => "Array "+i.mkString(" ")
case i => "null" +a
}
}
println( des("s"))
匹配数组
//匹配数组
for (i <- List(Array(0),Array(1,0),Array(0,1,0),Array(1,0,1))){
val res = i match {
case Array(0) => "0"
case Array(1,0) => "Array(1,0)"
case Array(0,1,0) => "Array(0,1,0)"
case Array(x,y) => "Array:" +x +" "+y //匹配数组中只有两个元素的数组
case Array(0, _*) => "以0开头的数组"
case Array(x,0,y) => "0在数组第二位"
case _ => "没有"
}
println(res)
}
匹配列表
//匹配列表
val list = List(1,2,3,4,5)
list match {
case first :: second :: rest => println(s"f:$first,s:$second,r:$rest") //匹配元素3个或以上的数组
case _=> println("null")
}
匹配元组
//匹配元组
for (tu <- List((1,1),(0,2),(1,5,4),(1,0,1),("hello",0.1))){
val res = tu match {
case (a,b) => "二元组:"+s"($a,$b)"
case (0,_) => "第一个元素是0的二元组"
case (a,1,_) => "1为第二个元素的元组"
case _ => "null"
}
println(res)
}
//在变量声明时匹配
val (x,y) =(1,2)
println(x+" "+y)
val List(f ,s ,_*) = List(1,2,3,4)
println(f+" "+s+" ")
val a :: b :: c = List(1,2,3,4,5,6)
println(a,b,c)
for推导式模式匹配
// for推导式模式匹配
val list : List[(String,Int)] = List(("a",1),("b",2))
//将list元素直接定义为元组,对变量赋值
for ((word,count) <- list ){
println(word+" ",count)
}
//不考虑某个位置的变量,只遍历key或value
for ((word,_) <- list){
println(word)
}
//可以指定某个位置的值是多少
for (("a",count) <- list){ //只输出key为a的元组的value
println(count)
}
匹配对象
基本语法
class User(val name: String, val age: Int)
object test {
def main(args: Array[String]): Unit = {
val s = new S1("name",20)
//实例内容进行匹配
val rs = s match {
case S1("name",20) => "yes"
case _ => "no"
}
println(rs)
}
}
//定义类
class S1(val name :String,val age : Int)
//定义伴生对象
object S1 {
def apply(name: String, age: Int): S1 = new S1(name, age)
//必须实现unapply方法 ,用来对对象属性进行拆包
def unapply(s1: S1): Option[(String, Int)] = {
if (s1 == null){
None
}else {
Some((s1.name,s1.age))
}
}
}
- val user = User("zhangsan",11),该语句在执行时,实际调用的是 User 伴生对象中的 apply 方法,因此不用 new 关键字就能构造出相应的对象。
- 当将 User("zhangsan", 11)写在 case 后时[case User("zhangsan", 11) => "yes"],会默 认调用 unapply 方法(对象提取器),user 作为 unapply 方法的参数,unapply 方法 将 user 对象的 name 和 age 属性提取出来,与 User("zhangsan", 11)中的属性值进行 匹配
- case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功, 属性不一致,或返回 None,则匹配失败。
- 若只提取对象的一个属性,则提取器为 unapply(obj:Obj):Option[T]
- 若提取对象的多个属性,则提取器为 unapply(obj:Obj):Option[(T1,T2,T3…)]
- 若提取对象的可变个属性,则提取器为 unapplySeq(obj:Obj):Option[Seq[T]
样例类
语法:
case class Person (name: String, age: Int)
- 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中 自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。
- 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例 类可以直接使用模式匹配,而无需自己实现 unapply 方法。
- 构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)
object mc {
def main(args: Array[String]): Unit = {
val s = S2("name",20)
//实例内容进行匹配
val rs = s match {
case S2("name",20) => "yes"
case _ => "no"
}
println(rs)
}
}
//定义样例类
case class S2(name: String,age : Int )
偏函数匹配
偏函数定义:
val second: PartialFunction[List[Int], Option[Int]] = {
case x :: y :: _ => Some(y)
}
原理:
上述代码会被 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)
}
}