11 模式匹配
11.1 基本语法
Scala中的模式匹配类似于Java中的switch - case 语句。可以按照指定的规则对数据进行匹配。
-
模式匹配主要用于规则匹配,模式匹配语法中没有break操作,执行完毕后,直接退出。
-
模式匹配中的_下划线表示任意值,类似于java中的default操作
但是不同的是java中的default操作,不管放在前面还是后面,都是最后执行。
但是scala中的case _ 放在前面,后面的就执行不到了。
-
模式匹配主要目的是将数据匹配上,必须匹配上,如果没有匹配条件会报错!
object Test1_Match {
def main(args: Array[String]): Unit = {
//TODO 匹配规则 - 基本语法
print("please enter a word:")
val str = scala.io.StdIn.readLine()
val describe = str match {
case "scala" => "SCALA"
case "spark" => "SPARK"
case "hadoop" => "HADOOP"
case _ => "else subject"
}
println(describe)
}
}
11.2 匹配常量
def describe(x: Any) = x match {
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
}
11.3 匹配类型
-
模式匹配中集合是不考虑泛型的
也就是说List不管里面放什么类型的数据,只要它是List,那就能够匹配上。
-
模式匹配中Scala的Array的泛型是特殊的
可以理解为Array[String]和Array[Int]是两种不同的类型,因为Java中数组没有泛型的概念,编译成java后其实就是String[]和Int[]所以这是两个不同的类型。
//TODO 匹配类型
def describe(x: Any) = x match {
case i: Int => s"${i} * 2 = ${i * 2}"
case s: String => "type is String"
case l: List[_] => "List do not have generic"
case a: Array[String] => "Array[String] is a type"
case e => "something else"
}
println(describe(10))
println(describe("Tom"))
println(describe(List(1, 2, 3)))
println(describe(List("1", "2", "3")))
println(describe(Array(1, "2", "3")))
11.4 匹配数组
//TODO 匹配数组
for (arr <- Array(
Array(1),
Array(0, 0, 1),
Array('a', '3'),
Array(1, 3),
Array("hello", 90, 99, 100)
)){
val result = arr match {
case Array(x) => "array has one param"
case Array(0, _*) => "array started with 0, and other param"
//这里的Array数组内不能放不同类型的数据,Array('a', 3),这样就不行。
//因为数组只能放一种类型数据。比如String[],比如Char[]
//这里是判断数组内的类型
case Array(x: Char, _) => "array started type is char , and two param"
case Array(x, y) => "array has two param"
case _ => "something else"
}
println(result)
}
11.5 匹配列表
//TODO 匹配列表
for (list <- Array(
List(1),
List(0, 0, 1),
List('a', '3'),
List('a', "name"),
List(1, 9, 2)
)){
val result = list match {
case List(x) => "list has one param"
case List(0, _*) => "list start with 0, and other param"
//可以匹配列表里的元素的类型
case List(x: Char, y: String) => "list has two param, and first type is char , second type is string"
case List(x, y) => "list has two param"
case _ => "something else"
}
println(result)
}
11.6 匹配元组
//TODO 匹配元组
for(tuple <- Array(
(0, 1),
(1, "string"),
(1, 1, 3),
(1, 2)
)){
val result = tuple match {
case (0, _) => "start with 0, and tow param"
case (x: Int, y: String) => "Int and String"
case (1, _, 3) => "1, _, 3"
case (_, 2) => "_, 2"
case _ => "something else"
}
println(result)
}
11.7 匹配对象
-
scala中匹配对象并不是真正的匹配对象,其实就是匹配对象的所有属性是否相同,
-
对象属性的比较是scala编译器完成的,但是伴生对象中应该有一个unapply方法
apply 方法是一个通过属性创建对象的过程
unapply 方法是一个通过对象提取属性的过程
object Test1_Match_6 {
def main(args: Array[String]): Unit = {
//TODO 模式匹配 - 匹配对象
val user = new User("Tom", 23)
//scala中匹配对象并不是真正的匹配对象
//所谓的匹配对象,其实就是匹配对象的所有属性是否相同
//这里对象的属性比较由scala自动完成,但是需要遵循特殊的规则
//伴生对象中应该有一个unapply方法
//apply方法是一个通过属性创建对象的过程
//unapply方法是一个通过对象提取属性的过程
user match {
//匹配对象中的所有属性!必须要有unapply方法
case User("Tom", 213) => println("zhangsan用户")
case _ => println("其他用户")
}
}
class User(val name: String, val age: Int)
object User{
def apply(name: String, age: Int): User = new User(name, age)
def unapply(arg: User): Option[(String, Int)] = {
Option((arg.name, arg.age))
}
}
}
使用样例类的方式匹配对象
object Test1_Match {
def main(args: Array[String]): Unit = {
//TODO 匹配对象
val user = User("Tom", 'M')
user match {
case User("Tom", 'F') => println("Tom")
case _ => println("other user")
}
}
case class User(var name: String, val gender: Char)
}
11.8 样例类
- 样例类就是使用case关键字声明的类
- 样例类仍然是类,和普通的类相比,只是自动生成了伴生对象,并且伴生对象内自动提供了:apply()、unapply()、toString()、equals()、hashCode()、copy()
- 样例类在编译时,自动实现了可序列化接口
- 一般情况下,样例类就是没有主题内容,
- 样例类在构造对象时,构造参数可以不用声明为var和val,默认使用val,如果想改可以显示声明为var
object Test1_Match_7 {
def main(args: Array[String]): Unit = {
//TODO 模式匹配 - 样例类
// val user = User
val tom = User("Tom", 24)
val jerry = User.apply("Jerry", 42)
tom match {
case User("Tom", 23) => println(s"name=${tom.name}, age=${tom.age}")
case _ => println("other user")
}
}
//类前可以使用case关键字,这样的类称为样例类
//样例类在编译时,自动实现了可序列化接口
//样例类在编译时,自动生成伴生对象
//样例类也是一个类,所以可以应用在任意场合
//一般情况下,样例类就是没有主体内容
//样例类构造对象时,构造参数可以不用声明为var或val,默认使用val
//如果想要更改,那么可以声明为var
case class User (val name: String, var age: Int)
}
11.9 应用场景
① 变量声明
//TODO 应用场景
val (id, name, age) = (1, "Tom", 23)
println(s"id=${id}, name=${name}, age=${age}")
② 循环匹配
val map = Map(("a", 1), ("b", 2), ("c", 3))
//循环输出,赋值给k-v
for ((k, v) <- map){
println(k+v)
}
//过滤掉v不是2的数据
for ((k, 2) <- map){
println(k,2)
}
//过滤掉v=2的数据
for ((k, v) <- map){
if (v != 2){
println(k, v)
}
}
//TODO 使用偏函数过滤
//过滤当v!=2,变成k-0
// val iterable = map.collect { case (k: String, v: Int) =>{
// if (v == 2)
// (k, v)
// else
// (k, 0)
// }}
//过滤当v=2,变成k-0
val iterable = map.collect { case (k: String, v: Int) => {
if (v != 2)
(k, v)
else
(k, 0)
}}
println(iterable)
③ 函数参数
//TODO 功能函数中使用模式匹配
//将数量都乘以2
val map = Map((("河北", "鞋子"), 10), (("河南", "衣服"), 26))
//注意和功能函数一起使用需要将map()改为大括号{},因为编译器以为传了两个参数呢~
val result: Map[String, (String, Int)] = map.map {
case ((prv, item), num) => (prv, (item, num * 2))
}
println(result)
11.10 偏函数
-
偏函数就是使用collect{}来对符合条件的数据,进行操作。
注意需要使用collect方法,使用大括号!!!
-
大括号内写匹配模式
object Test1_Match_8 {
def main(args: Array[String]): Unit = {
//TODO 模式匹配 - 偏函数
//将List(1, 2, 3, 4, "test", true)这个集合中,Int类型*2,去掉其他类型
val list = List(1, 2, 3, 4, "test", true)
// val result = list.map {
// case i: Int => i * 2
// case s => s
// }.filter(_.isInstanceOf[Int])
//如果不适用模式匹配的话,那么就得这样做,需要isInstanceOf判断类型,然后asInstanceOf转换类型
// val result = list.map(t => {
// if (t.isInstanceOf[Int]) {
// t.asInstanceOf[Int] * 2
// } else {
// t
// }
// })
//TODO 采用偏函数
val result = list.collect { case i: Int => i * 2 }
println(result)
}
}