Scala笔记--模式匹配

Posted 幼儿园园草

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala笔记--模式匹配相关的知识,希望对你有一定的参考价值。

模式匹配(pattern matching)在Scala被广泛使用的特性中排在第二位,仅次于函数值和闭包。Scala对于模式匹配的出色支持意味着,在并发编程中在处理Actor接收到的消息时,将会大量地使用它。

Scala的模式匹配非常灵活,可以匹配字面量和常量,以及使用通配符匹配任意的值、元组和列表,甚至还可以根据类型以及判定守卫来进行匹配。

1 基础用法

scala的模式匹配类似于Java的Switch语句,但是比Switch语句强大得多。

1.1 入门案例

val i: Int = 5
val s: String = i match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case 4 => "four"
  case _ => "other"
}
println(s)

1.2 匹配函数参数

我们可以通过匹配函数的参数来进一步简化二元加减乘除等操作。

def matchDualOp(a: Int, b: Int, op: Char): Int = op match {
  case '+' => a + b
  case '-' => a - b
  case '*' => a * b
  case '/' => a / b
  case _ => -1
}
println(matchDualOp(2, 1, '+'))
println(matchDualOp(2, 1, '-'))
println(matchDualOp(2, 1, '*'))
println(matchDualOp(2, 1, '/'))
//    println(matchDualOp(2,0,'/'))         // 报错 / by zero

1.3 模式守卫

1.2的例子其实有些地方需要改进,因为除法操作中,b不能为0,所以这里可以使用模式守卫进行改进。

def matchDualOp_(a: Int, b: Int, op: Char): Int = op match {
  case '+' => a + b
  case '-' => a - b
  case '*' => a * b
  case '/' if b != 0 => a / b
  case _ => {
    print("无法匹配")
    -1
  }
}
println(matchDualOp_(2, 1, '+'))
println(matchDualOp_(2, 1, '-'))
println(matchDualOp_(2, 1, '*'))
println(matchDualOp_(2, 1, '/'))
println(matchDualOp_(2, 0, '/'))

2 集合匹配

2.1 匹配常量

def describeConst(x: Any): String = x match {
  case 1 => "Int one"
  case "hello" => "String hello"
  case true => "Boolean true"
  case '+' => "Char +"
  case _ => ""
}
println(describeConst("hello"))
println(describeConst('+'))
println(describeConst(0.3))

2.2 匹配数据类型

def describeType(x: Any): String = x match {
  case i: Int => "Int " + i
  case s: String => "String " + s
  case list: List[String] => "List " + list
  case array: Array[Int] => "Array[Int] " + array.mkString(",")
  case a => "Something else: " + a
}
println(describeType(35))
println(describeType("hello"))
println(describeType(List("hi", "hello")))
println(describeType(List(2, 23)))
println(describeType(Array("hi", "hello")))
println(describeType(Array(2, 23)))

2.3 匹配数组

for (arr <- List(
  Array(0),
  Array(1, 0),
  Array(0, 1, 0),
  Array(1, 1, 0),
  Array(2, 3, 7, 15),
  Array("hello", 1, 30),
)) {
  val result:String = 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 _ => "something else"
  }
  println(result)

2.4 匹配列表

    for (list <- List(
      List(0),
      List(1, 0),
      List(0, 0, 0),
      List(1, 1, 0),
      List(88),
      List("hello")
    )) {
      val result:String = list match {
        case List(0) => "0"
        case List(x, y) => "List(x, y): " + x + ", " + y
        case List(0, _*) => "List(0, ...)"
        case List(a) => "List(a): " + a
        case _ => "something else"
      }
      println(result)
    }

2.5 匹配元组

    for (tuple <- List(
      (0, 1),
      (0, 0),
      (0, 1, 0),
      (0, 1, 1),
      (1, 23, 56),
      ("hello", true, 0.5)
    )){
      val result = tuple match {
        case (a, b) => "" + a + ", " + b
        case (0, _) => "(0, _)"
        case (a, 1, _) => "(a, 1, _) " + a
        case (x, y, z) => "(x, y, z) " + x + " " + y + " " + z
        case _ => "something else"
      }
      println(result)

2.6 通用匹配

这种方式很像python的接收参数的用法

package com.lrm.demo08

/**
 * @author RuiMing Lin 
 * @date 2021-06-05 10:06
 * @description 元祖匹配
 */
object demo3 {
  def main(args: Array[String]): Unit = {
    // 1. 在变量声明时匹配
    val (x, y) = (10, "hello")
    println(s"x: $x, y: $y")

    val List(first, second, _*) = List(23, 15, 9, 78)
    println(s"first: $first, second: $second")

    val fir :: sec :: rest = List(23, 15 , 9, 78)
    println(s"first: $fir, second: $sec, rest: $rest")
    println("=====================")

    // 2. for推导式中进行模式匹配
    val list: List[(String, Int)] = List(("a", 12), ("b", 35), ("c", 27), ("a", 13))
    // 2.1 原本的遍历方式
    for (elem <- list){
      println(elem._1 + " " + elem._2)
    }
    println("-----------------------")

    // 2.2 将List的元素直接定义为元组,对变量赋值
    for ((word, count) <- list ){
      println(word + ": " + count)
    }
    println("-----------------------")

    // 2.3 可以不考虑某个位置的变量,只遍历key或者value
    for ((word, _) <- list)
      println(word)
    println("-----------------------")

    // 2.4 可以指定某个位置的值必须是多少
    for (("a", count) <- list){
      println(count)
    }
  }
}

3 对象匹配

3.1 unapply

做对象的模式匹配时,必须实现一个unapply方法,用来对对象属性进行拆解

package com.lrm.demo08

/**
 * @author RuiMing Lin 
 * @date 2021-06-05 10:07
 * @description
 */
object demo4 {
  def main(args: Array[String]): Unit = {
    val student = new Student("alice", 19)
    // 针对对象实例的内容进行匹配
    val result = student match {
      case Student("alice", 18) => "Alice, 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))
    }
  }
}

3.2 样例类

case类是特殊的类,可以使用case表达式来进行模式匹配。case类很简洁,并且容易创建,它将其构造参数都公开为值。可以使用case类来创建轻量级值对象,或者类名和属性名都富有意义的数据持有者。

package com.lrm.demo08

/**
 * @author RuiMing Lin 
 * @date 2021-06-05 10:07
 * @description 样例类
 */
object demo5 {
  def main(args: Array[String]): Unit = {
    val student = Student1("alice", 18)

    // 针对对象实例的内容进行匹配
    val result = student match {
      case Student1("alice", 18) => "Alice, 18"
      case _ => "Else"
    }
    println(result)
  }
}

// 定义样例类
case class Student1(name: String, age: Int)

以上是关于Scala笔记--模式匹配的主要内容,如果未能解决你的问题,请参考以下文章

scala学习笔记-模式匹配(16)

Scala笔记--模式匹配

Scala笔记--模式匹配

Scala 模式匹配详解

Scala 学习笔记之集合

Scala 基础(十三):Scala 模式匹配