Scala - 模式匹配

水善利万物而不争,处众人之所恶,故几于道

目录

  1. 基本语法
  2. 模式守卫
  3. 匹配常量
  4. 匹配类型
  5. 匹配数组
  6. 匹配列表
  7. 匹配元组

    7.1 模式匹配操作元组

    7.2 练习

  8. 匹配对象
  9. 样例类

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

1. 基本语法

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

var a:Int = 10
var b:Int = 20
var op:Char = 'M'

val res: Any = op match {
  case '+' => a + b
  case '-' => a - b
  case '*' => a * b
  case '/' => a / b
  case _ => "操作不合法"
}

println(res)

2. 模式守卫

  参考循环守卫。模式守卫就是在模式匹配中增加条件守卫

  求绝对值的demo:

def abs(x:Int) = x match {
  case a:Int if a>=0 => a
  case b:Int if b<0 => -b
  case _ => "type illegal"
}

//  println(abs(9))
println(abs(-5))

3. 匹配常量

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

//    匹配常量
def matchVal(x:Any) = x match {
  case 5 => "Int five"
  case "hello" => "String hello"
  case true => "Boole true"
  case '+' => "Char +"
}

println(matchVal(5))

4. 匹配类型

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

def matchType(x: Any) = x match {
  case i: Int => "Int " + i
  case s: String => "String hello"
  //      case m:List[_] => "List"  List[_]表示所有类型
  case m: List[String] => "List"
  case c: Array[Int] => "Array[Int]"
  case noFindType => "no find match type: " + noFindType
}

//    println(matchType("test"))

// 泛型擦除,在匹配的时候,和泛形无关
    println(matchType(List("a", "b", "c")))
    println(matchType(List(1,2,3)))

//数组是个例外,数组没有泛型擦除,数组在匹配的时候,会保留泛型
// 因为数组在编译后是 Array[Int] --> Int[]   Array[String] --> String[]
    println(matchType(Array("a")))

5. 匹配数组

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

for (arr <- List(
  Array(0),
  Array(1, 0),
  Array(0, 1, 0),
  Array(1, 1, 0),
  Array(1, 1, 0, 1),
  Array("hello", 90))) { // 对一个数组集合进行遍历

  val result = arr match {
    case Array(0) => "0" //匹配Array(0) 这个数组

    case Array(x, y) => x + "," + y //匹配有两个元素的数组,然后将将元素值赋给对应的x,y

    case Array(0, _*) => "以0开头的数组" //匹配以0开头和数组

    case _ => "something else"
  }

  println("result = " + result)
}

6. 匹配列表

方式一:

for( list <- List(
                List(0),
                List(1,0),
                List(0,0,0),
                List(1,0,0),
                List(88))){

  val res = list match {
    case List(0) =>"0"  // 匹配List(0)
    case List(x,y) => x +","+y   //匹配有两个元素的List
    case List(0,_*) => "0...."
    case List(x) => x  // 匹配只有一个元素的List
    case _ => "something else"
  }
  println(res)
}

输出结果:
0
1,0
0....
something else
88

方式二:
运算顺序从右到左,把b加到c里面,再把a加到c里面

val list:List[Int] = List(1,2,5,6,7)

list match{
  case a::b::c => println(a+" - "+b+" - "+c)
  case _ => println("no match")
}

输出结果:
1 - 2 - List(5, 6, 7)

7. 匹配元组

for(tuple <- List(
                (0,1),
                (1,0),
                (1,1),
                (1,0,2))){
  val result = tuple match{
    case (0,_) => "0....."   // 第一个元素是0的元组
    case (y,0) => ""+ y + "0"  // 匹配后一个元素是0的对偶元组
    case (a,b) => ""+a+ " " +b
    case _ => "no match"
  }
  println(result)
}

7.1 模式匹配操作元组

val list: List[(String, Int)] = List(("a", 1), ("b", 2), ("c", 3))

// 对list进行遍历,输出元组中的第一个元素  可读性差
for (elem <- list) {
  println(elem._1)
}

// 特殊的模式匹配1   可读性好
for ((word:String,count:Int) <- list) {
  println(word)
}

  for ((word,_) <- list) {
    println(word)
  }

for(("a",count) <- list){
  println(count)
}

==================================================
//特殊的模式匹配2  在模式匹配的时候,给元组元素命名
val (id,name,age): (Int, String, Int) = (100, "jingjing", 18)
println(name)

7.2 练习

将元组中第一个元素不变,第二个元素的值乘2

val list = List(("a", 1), ("b", 2), ("c", 3))

val newList: List[(String, Int)] = list.map(
  tuple =>{    // 只有一个参数,参数是遍历到的每个元组
    tuple match {  // 遍历到每个元组后去进行模式匹配
      case (word,count) => (word,count*2)
    }
  }
 )
println(newList)

对上面的代码进行优化,简写

 1. 如果匿名函数中,使用模式匹配case,要求必须使用花括号扩起来
 2. 如果一个函数参数列表中,只有一个参数,那么参数列表的小括号可以省略

val list = List(("a", 1), ("b", 2), ("c", 3))

val newList: List[(String, Int)] = list.map{
      case (word,count) => (word,count*2)
}
println(newList)

传进来的参数可以省略

强化练习:

val list = List(("a", ("a", 5)), ("b", ("b", 10)), ("c", ("c", 20)))

val newList: List[(String, (String, Int))] = list.map {
  case (flag, (word, count)) => (flag, (word, count * 2))
}
println(newList)

8. 匹配对象

  匹配对象的时候,要求伴生对象类中有unapply方法,用于获取对象的属性

  Option类型有两个子类型:Some和None。Some表示一个值存在的情况,它包装了真实的值。None表示一个值不存在的情况,它不包含任何值。

  Option对象可以用于代替使用null来表示值的缺失。它提供了一种类型安全的方式来处理可能为空的值,避免了空指针异常。

class User(var name:String ,var age:Int){}
object User{
  // 根据属性创建对象
  def apply(name: String, age: Int): User = new User(name, age)

  // 根据对象获取对象的属性
  def unapply(arg: User): Option[(String, Int)] = {
    if (arg == null){
      return None
    }else{
      return Some(arg.name,arg.age)
    }
  }
}


object S04_TestMatch {
  def main(args: Array[String]): Unit = {

    val qcln: User = User("qcln", 18)

    val res: String = qcln match {
      case User("test", 18) => "match success"
      case _ => "match fail"
    }
    println(res)
  }
}

9. 样例类

在普通的类定义前面加上case ,这样的话在匹配对象的时候就不用自己手动写apply和unapply方法了,他会自己提供。

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

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

case class User05(var name:String, var age:Int){}

object S05_TestMatch {
  def main(args: Array[String]): Unit = {

    val qcln: User05 = User05("qcln", 18)

    val res: String = qcln match {
      case User05("test", 18) => "match success"
      case _ => "match fail"
    }
    println(res)
  }
}

你可能感兴趣的:(Scala,scala,开发语言,模式匹配)