模式匹配-基础使用

16 阅读5分钟

一.分析问题并解决

根据一个值输出另一个与之对应的值,很容易就想到if else

object ProvinceCodeLookup {
    def main(args: Array[String]): Unit = {
        val code = "42"
        val provinceName = getProvinceName(code)
        println(provinceName)
    }
    def getProvinceName(code: String): String = {
        if (code == "42") {
            "湖北"
        } else if (code == "33") {
            "浙江"
        } else if (code == "11") {
            "北京"
        } else if (code == "31") {
            "上海"
        } else {
            "未找到对应的省份"
        }
    }
}

在java中有case语句,可以怎么写?

直接用 match case 来改造。

 def getProvinceName(code: String): String = code match {
        case "42" => "湖北"
        case "33" => "浙江"
        case "11" => "北京"
        case "31" => "上海"
        case _ => "未找到对应的省份"
    }
package matchcase

object matchcase01 {
  def main(args: Array[String]): Unit = {
    println(getProvinceName(11))
    println(getProvinceName(42))
    println(getProvinceName(12))
  }
  def getProvinceName(code:Int):String = {
    code match {
      case 42 => "湖北"
      case 11 => "北京"
      case _ => "未知"
    }
  }
}

二.match case的基本格式

格式如下
value match {
  case pattern1 => result1
  case pattern2 => result2
...
  case patternN => resultN
case _ => 其他
}

执行流程是:如果value匹配到了pattern1,就执行结果1,如果都没有匹配到,就执行 _ 对应的内容。

根据数值,输出对应的英文

val num = 5
val result = num match {
  case 1 => "One"
  case 2 => "Two"
  case 3 => "Three"
  case 4 => "Four"
  case 5 => "Five"
  case _ => "Other"
}
println(result)

练习时,请注意两种特别的情况:

(1) 如果把case _ 放在前面会怎么样?

(2) 如果省略了case _ 并且没有匹配到的内容,会怎么样?

三.高阶匹配之元组元素数量

前面的匹配都是精准匹配:变量和值是相等的。但是呢,scala中的模式匹配的规则是非常强大的,不一定是精准的匹配值,还可以根据元组的元素的个数来匹配。

val t1 = (2,3)
val t1 = (2,3,4)
val t1 = (2,3,4,5)  
def matchAmount(value: Any): Unit =  
   t1 match {
     case (first, second) => "有两个元素"
     case (x1,x2,x3) => "有三个元素"
     case _ => "其他情况"
}  
}
matchAmount(t1)
package matchcase
// match case 的用法
// (1)类似于if else if 这种多分支选择结构,精确匹配值
// 1. case _ 是不可省略的。如果匹配不成功,又没有case _,程序会报错
// 2. case _ 必须要放在最后。
// (2)匹配元组元素的数量

object matchcase02 {
  def main(args: Array[String]): Unit = {
    val xiaohong = (100,100,100)
    val xiaoming = (89,98)

    getScore(xiaohong)
    getScore(xiaoming)
    getScore(1,2,3,4)
  }

  def getScore(score:Any):Unit = {
    score match {
      case (a,b,c) => println("元组中有三个元素: a = " + a + " b = " + b + " c = " + c)
      case (a,b) => println("元组中有两个元素: a = " + a + " b = " + b)
      case _ => println("未知")
    }
  }
}

四.高阶匹配之匹配元素特征

模式匹配还可以根据数组元素的个数,元素的特征来匹配。

例如如下的格式:

数组 match {
case Array(1,x,y) => 匹配到数组,长度为3,且第一个元素为1
case Array(0) =>匹配到数组:长度为1,且只有一个元素0  
case Array(1,_*) =>匹配到数组:长度为n,第一个元素为1
    case _ => 其他
}
val arr1 = Array(0)  //长度为1  
val arr2 = Array(1,2,3)// 首元素为1  
val arr3 = Array(0,2,8,10,11)  
val arr4 = Array(1,2,8,10,11)    
arr4 match {  
  case Array(1,x,y) => println("匹配到数组,长度为3,且第一个元素为1")  
  case Array(0)=>println("匹配到数组:长度为1,且只有一个元素0")  
  case Array(0,_*) =>println("匹配到数组:长度为n,第一个元素为0")  
  case _ => println("其他")  
}
package matchcase

// (4)匹配元素特征
object matchcase04 {
  def main(args: Array[String]): Unit = {
    testType(Array(1,2,3))
    testType(Array(1,2,3,4))
    testType(Array(11,2,3,4))
    testType(Array(11,1,3,4))
  }

  def testType(arr:Any):Unit = {
    arr match {
      case Array(1,x,y) => println("arr是一个数组,有三个元素,第一个是1")
      case Array(1,x,y,z) => println("arr是一个数组,有四个元素,第一个是1")
      case Array(x,1,y,z) => println("arr是一个数组,有四个元素,第二个是1")
      case _ => println("未知")
    }
  }
}

五.高阶匹配之变量类型匹配

除了格式匹配之后,还可以对变量的类型进行匹配。

格式如下:

对象名 match {
    case 变量名1:类型1  => 表达式1  
    case 变量名2:类型2  => 表达式2  
    case 变量名3:类型3  => 表达式3
    // 其他case语句...  
    casee _ => 表达式
}

如果变量名没有被使用到,可以使用_代替。 例如: _:Int =>

需求:
1.定义一个变量为Any类型,然后分别给它赋值不同的类型的数据。

2.对这个变量做模式匹配

def processValue(value: Any): Unit =
value match {
    case i: Int => println(s"这是一个整数:$i")
    case d: Double => println(s"这是一个双精度浮点数:$d")
    case s: String => println(s"这是一个字符串:$s")
    case b: Boolean => println(s"这是一个布尔值:$b")
    case _ => println("这是其他类型")
}  
}  
matchType(5)  
matchType("Hello")
package matchcase

// (3)匹配变量类型
object matchcase03 {
  def main(args: Array[String]): Unit = {
    testType(1)
    testType(1.1)
    testType("1")
  }

  def testType(i:Any):Unit = {
    i match {
      case x:Int => println("当前变量是: Int")
      case x:Double => println("当前变量是: Double")
      case _ => println("未知")
    }
  }
}

六.高阶匹配之匹配案例类

模式匹配还根据案例类的不同,匹配不同的案例类和其中的字段信息。例如格式

对象 match {
case 样例类类型1(字段1,字段2)=> 表达式
case 样例类类型2(字段1,字段2,字段3)=> 表达式
    case _ => 其他
}

注意:样例类1中的字段个数要与之对应。

case class Circle(radius: Double)
case class Rectangle(width: Double, height: Double)  
def calculateArea(shape: Any): Double = shape match {
    case Circle(r) => Math.PI * r * r
    case Rectangle(w, h) => w * h
}
val circle = Circle(3.0)
val rectangle = Rectangle(4.0, 5.0)
println(calculateArea(circle))
println(calculateArea(rectangle))

当传入Circle类型时,匹配case Circle(r)并按照圆的面积公式计算;当传入Rectangle类型时,匹配case Rectangle(w, h)并按照矩形面积公式计算。

package matchcase

// match case 的用法

// (5)样例类及其属性

object matchcase05 {
  // 定义一个样例类:圆形。它有一个属性:半径
  case class Circle(radius:Double)
  // 定义一个样例类:矩形。它有两个属性:长和宽
  case class Rectangle(width:Double,height:Double)

  // 定义一个方法,用来求圆形,矩形的面积
  def getArea(obj:Any):Unit = {
    obj match {
      case Circle(radius) => println("圆形的面积是: " + radius * radius * 3.14)
      case Rectangle(width,height) => println("矩形的面积是: " + width * height)
      case _ => println("未知")
    }
  }

  def main(args: Array[String]): Unit = {
    getArea(Circle(2))
    getArea(Rectangle(2,3))
    getArea("abc")
  }
}