scala教程:模式匹配

介绍

模式匹配,写法类似 JAVA 的 switch 语句,但不需要 break

功能非常强大,如:

  • 判断值
  • 判断类型

语法

val res = 变量/常量 match {
    case 匹配值1 => 返回值1
    case 匹配值2 => 返回值2
    ...
}

匹配字面值

匹配字面值,类似 java 的 switch 语句

val i = 5
val res = i match {
  case 1 => "星期一"
  case 2 => "星期二"
  case 3 => "星期三"
  case 4 => "星期四"
  case 5 => "星期五"
  case 6 => "星期六"
  case 7 => "星期日"
  case _ => "无效日期" // 类似 java switch 的 default
}

println(res)

执行结果:

星期五

总结

  • 所有 case 都不匹配,则 匹配 case _,类似 java switch 语句的 default。如果没有 case _ 会报错

  • 与 java switch 语句不同,case 后不需要 break

搭配函数、方法

将上面的代码 封装 成 函数 或 方法,隐藏细节,调用起来更加方便

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

  def week(i:Int) : String = i match {
    case 1 => "星期一"
    case 2 => "星期二"
    case 3 => "星期三"
    case 4 => "星期四"
    case 5 => "星期五"
    case 6 => "星期六"
    case 7 => "星期日"
    case _ => "无效日期"
  }

  println( week(1))
  println( week(5))
  println( week(7))
  println( week(10))
}

匹配不同的类型 的字面值

可以匹配 任意类型的 字面值。if 语句 或 java 的 switch 语句,都没有此功能

// 由于可传入不同类型的形参,所以形参类型是 Any
def m(x:Any) = x match {
  case "one" => "字符串类型"
  case 1 => "整型"
  case 1.1 => "浮点类型"
  case true => "布尔类型"
  case _ => "未知类型"
}
println( m("one"))
println( m(1))
println( m(1.1))
println( m(true))
println( m( '汉' ))

执行结果:

字符串类型
整型
浮点类型
布尔类型
未知类型

匹配类型

注意:这里是 匹配类型,不是匹配字面值

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

  def getType(x: Any) = x match {
    case i: String => "字符串类型"
    case i: Int => "整型"
    case i: Double => "浮点类型"
    case i: Boolean => "布尔类型"
    case _ => "未知类型"
  }

  println(getType("one"))
  println(getType(1))
  println(getType(1.1))
  println(getType(true))

}

集合的泛型会擦除(数组不会擦除)

def main(args: Array[String]): Unit = {
  // 匹配类型
  def getType(i: Any): String = i match {
    // List 后面的 必须有泛型,编译时会擦除泛型
    case i: List[Int] => "List,泛型是Int"  
    // Array 后面的 必须有泛型
    case i: Array[Int] => "Array,泛型是Int"
    case _ => "未知类型"
  }
  //未知类型,数组不会发生擦除泛型
  println("res:" + getType( Array("李雷","韩梅梅")  )  )
  //Array,泛型是Int
  println("res:" + getType( Array(1,200))   ) 

  //List,泛型是Int,List 会发生擦除泛型
  println("res:" + getType( List("李雷", "韩梅梅"))) 
  //List,泛型是Int,泛型是Int
  println("res:" + getType( List(1, 200))) 

}

解释:对于 集合 来说,泛型会被擦除,所以会导致 匹配不正确。数组不会擦除

集合擦除泛型的原因:

反编译如下:

匹配数组

根据传入数组的元素,进行匹配

def main(args: Array[String]): Unit = {
  def m(arr:Array[Int]) = arr match {
    case Array(1,2,3) => "一共3个元素,且是:1、2、3"
    case Array(1,2,3, x) => "一共4个元素,最后一个元素可以是任意整数"
    case Array(x ,3, y) => "一共3个元素,第二个元素是3"
    case Array(3, _*) => "第一个元素是3,后面可以是任意整数,*表示任意个元素"
    case _ => "未知"
  }
  println( m(Array(1,2,3)))
  println( m(Array(1,2,3,100)))
  println( m(Array(1,3,100)))
  println( m(Array(3,40,100)))
}

匹配列表

功能同 匹配数组

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

  def m(arr: List[Int]) = arr match {
    case List(1, 2, 3) => "一共3个元素,且是:1、2、3"
    case List(1, 2, 3, x) => "一共4个元素,最后一个元素可以是任意整数"
    case List(x, 3, y) => "一共3个元素,第二个元素是3"
    case List(3, _*) => "第一个元素是3,后面可以是任意整数,且长度任意"
    case _ => "未知"
  }

  println(m(List(1, 2, 3)))
  println(m(List(1, 2, 3, 100)))
  println(m(List(1, 3, 100)))
  println(m(List(3, 40, 100)))
}

匹配元组

功能同 匹配数组

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

  def m(arr: Any ) = arr match {
    case (1, 2, 3) => "一共3个元素,且是:1、2、3"
    case (1, 2, 3, x) => "一共3个元素,最后一个元素可以是任意整数"
    case (x, 3, y) => "一共3个元素,第二个元素是3"
    case _ => "未知"
  }

  println(m((1, 2, 3)))
  println(m((1, 2, 3, 100)))
  println(m((1, 3, 100)))
  println(m((3, 40, 100))) // 未知
}

匹配 for 表达式

使用 for 语句,查找集合中的某个元素时,可以用模式匹配简化写法

在 List 中,找出身高(第二个元素)是 170 的姓名

普通写法:

def main(args: Array[String]): Unit = {
  val list = List( ("李雷",183),("韩梅梅",165),("lucy",170),("lili",170))
  // 普通写法
  for (item <- list) {
    if ( item._2 == 170) {
      println(item._1)
    }
  }

模式匹配:

def main(args: Array[String]): Unit = {
  val list = List( ("李雷",183),("韩梅梅",165),("lucy",170),("lili",170))
  for( ( x,170) <- list ){
    println(x)
  }
}

模式守卫

匹配变量,与 java 的 switch 相比,可以实现 根据分数返回 优、良、中、差、不及格

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

  def score(i: Int): String = i match {
    case i if i>=90 => "优"
    case i if i>=80 => "良"
    case i if i>=70 => "中"
    case i if i>=60 => "差"
    case _ => "不及格"
  }

  println(score(92))
  println(score(85))
  println(score(77))
  println(score(62))
  println(score(35))
}

多行代码可以用 {}

如果 case => 后 有多行代码,可以用 {} 包裹

val i = 5
val res = i match {
  case 1 => "星期一"
  case 2=> {
        1 + 1 // 如果有多行代码可以用 {}
        "星期二"
      }
  case 3 => "星期三"
  case 4 => "星期四"
  case 5 => "星期五"
  case 6 => "星期六"
  case 7 => "星期日"
  case _ => "无效日期"
}

println(res)

原文出处:/show_1IX4Ph4KM6cl.html