🙆♂️🙆♂️ 写在前面
🏠 个人主页:csdn春和
📚 推荐专栏:更多专栏尽在主页!
JavaWeb专栏(从入门到实战超详细!!!)
SSM专栏 (更新中…)
📖 本期文章:Scala高级语法入门 (五) 一文彻底了解 Scala中的模式匹配
如果对您有帮助还请三连支持,定会一 一回访!🙋🏻♂️
📌本文目录
Scala中的模式匹配
1、什么是模式匹配
Scala中的模式匹配类似于Java中的switch语法,但是scala从语法中补充了更多的功能,可以按照指定的规则对数据或对象进行匹配, 所以更加强大。
我们先来看看java中的switch语句
public static void main(String[] args) {
int i = 20;
switch (i){
default:
System.out.println("other number");
break;
case 10:
System.out.println("10");
break;
case 20:
System.out.println("20");
break;
}
}
2、基本语法
模式匹配语法中,采用
match
关键字声明,每个分支采用case
关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _
分支,类似于Java中default语句。如果不存在case _分支,那么会发生错误。
示例代码:
object Scala_Match01 {
def main(args: Array[String]): Unit = {
val x: Int = 20
val y: Int = 10
var operator: Char = StdIn.readChar() // 从键盘读取数据
val result = operator match {
case '+' => x + y
case '-' => x - y
case '*' => x * y
case '/' => x / y
case '%' => x % y
case _ => "非法计算"
}
println(result)
}
}
3、匹配规则
3.1、匹配常量
// 1、匹配常量
def describe(x: Any) = x match {
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
}
3.2、匹配类型
需要注意的是集合中的泛型不会被匹配
// 2、匹配类型
def describe(x: Any) = x match {
case i: Int => "Int"
case s: String => "String hello"
case m: List[String] => "List"
case c: Array[Int] => "Array[Int]" // Array[Int] 整体当做一个类型
case someThing => "something else " + someThing // 这里的Something表示其他补匹配的情况 相当于_ java中的default
}
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
println(describe(list)) // List 模式匹配只匹配类型 不匹配泛型
println(describe(5))
3.3、匹配数组
// 3、匹配数组
for (arr <- Array(
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)
}
3.4、匹配列表
// 4、匹配列表
for (list <- Array(
List(0),
List(1, 0),
List(0, 0, 0),
List(1, 0, 0),
List(88))) {
val result = list match {
case List(0) => "0" //匹配List(0)
case List(x, y) => x + "," + y //匹配有两个元素的List
case List(0, _*) => "0 ..." // 以0开头
case _ => "something else"
}
println(result)
}
还可以进行下面的匹配:
val list: List[Int] = List(1, 2, 5, 6, 7)
list match {
case first :: second :: rest => println(first + "-" + second + "-" + rest)
case _ => println("something else")
}
val list: List[Int] = List(1, 2)
val list: List[Int] = List(1)
3.5、匹配元组
// 5、匹配元祖
for (tuple <- Array((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 _ => "something else" //默认
}
println(result)
}
3.6、应用场景
3.6.1、变量声明
// 场景1、变量声明
val (id, name, age) = (1, "zhangsan", 30)
println(name)
val Array(first, second, _*) = Array(1, 7, 2, 9)
println(s"first=$first,second=$second")
3.6.2、循环匹配
val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
for ((k, v) <- map) { //直接将map中的k-v遍历出来
println(k + " -> " + v) //3个
}
println("----------------------")
//遍历value=0的 k-v ,如果v不是0,过滤
for ((k, 0) <- map) {
println(k + " --> " + 0) // B->0
}
println("----------------------")
//if v >= 1 是一个过滤的条件
for ((k, v) <- map if v >= 1) {
println(k + " ---> " + v) // A->1 和 c->33
}
3.6.3、函数参数
val list = List(
("a", 1), ("b", 2), ("c", 3)
)
// 将value扩大两倍
val list1 = list.map {
case (k, v) => {
(k, v * 2)
}
}
println(list1)
看看如下数据解决需求
val list = List( (("湖北","鞋"),20), (("湖北","衣服"),40), (("湖北","电脑"),10) )
需求:把数据变为 把省份独立出来 点击次数扩大两倍 (“湖北”,(“鞋”,20 * 2))
普通写法:
val map = list.map(
t => {
val province = t._1._1
val product = t._1._2
val count = t._2
(province, (product, count * 2))
}
)
简化写法:
val map = list.map(
t => {
(t._1._1, (t._1._2, t._2 * 2))
}
)
但是我们说按顺序来肯定不好,过段时间我们就忘记这些个顺序表示的是哪些字段
采用模式匹配的写法
val map = list.map {
case ((provice, product), count) => {
(provice, (product, count * 2))
}
}
注意点:
1、匹配数据时候使用case关键字
2、case分支可能存在多个,如果使用模式匹配那么在map后要使用{},如果还是使用() 则会报错
3.7、匹配对象
object Scala_Match04 {
def main(args: Array[String]): Unit = {
// TODO 模式匹配 匹配对象
// 属性 去构造 对象
val user = getUser()
user match {
case User("张无忌", 20) => println("用户为张无忌")
case _ => println("匹配不成功!")
}
// 对象 得到 属性
}
class User {
var name: String = _
var age: Int = _
}
object User {
// object ==> attribute
def unapply(user: User): Option[(String, Int)] = {
Option((user.name, user.age))
}
// attribute ==> object
def apply(name: String, age: Int): User = {
val user = new User()
user.name = name
user.age = age
user
}
}
def getUser(): User = {
User("张无忌", 20)
}
}
4、样例类
1、样例类就是使用case关键字声明的类
2、样例类仍然是类,和普通类相比,只是其自动生成了伴生对象
,并且伴生对象中自动提供了一些常用的方法
,如apply
、unapply
、toString、equals、hashCode和copy。
3、样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。
4、构造器中的每一个参数都成为val,除非它被显式地声明为var(不建议这样做)
优化上述匹配对象的代码:
object Scala_Match05 {
def main(args: Array[String]): Unit = {
// TODO 模式匹配 样例类
val user = getUser()
user match {
case User("张无忌", 20) => println("用户为张无忌")
case _ => println("匹配不成功!")
}
}
case class User(name: String, age: Int)
def getUser(): User = {
User("张无忌", 20)
}
}
总结:
1、样例类会自动实现可序列化接口
2、样例类的构造参数直接能够作为属性进行使用,但是不能修改 如果要修改则需要使用var关键字进行声明
3、样例类会在编译时增加和重写了大量的方法
4、样例类自动生成伴生对象,自动声明了apply和unapply方法
5、偏函数
所谓的偏函数,其实就是对集合中符合条件的数据进行处理的函数偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为Int,但是我们只考虑数值为1的时候,数据该如何处理,其他不考虑。
基本语法:
def main(args: Array[String]): Unit = {
// TODO 模式匹配 偏函数
// 声明偏函数
val pf: PartialFunction[Any, Int] = { case i:Int => i+1 } // 将所有int型的数据加一
val list = List(1,2,3,4,"test")
// 应用偏函数
println(list.collect(pf))
}
所谓的偏函数就是只对满足条件的数据进行处理
像之前我们学习的map flatMap等函数都是全量函数
案例实操:
将该List(1,2,3,4,5,6,“test”)中的Int类型的元素乘以2,并去掉字符串。
不使用偏函数:
// 不使用偏函数
// 1、使用filter过滤掉字符串
val filter: Seq[Any] = list.filter(_.isInstanceOf[Int])
// 2、使用map转变数据结构
val res = filter.map(_.asInstanceOf[Int] * 2)
println(res)
使用偏函数
// 使用偏函数
val res = list.collect {
case x: Int => x * 2 // 使用模式匹配
}
println(res)
是只对满足条件的数据进行处理`
像之前我们学习的map flatMap等函数都是全量函数
案例实操:
将该List(1,2,3,4,5,6,“test”)中的Int类型的元素乘以2,并去掉字符串。
不使用偏函数:
// 不使用偏函数
// 1、使用filter过滤掉字符串
val filter: Seq[Any] = list.filter(_.isInstanceOf[Int])
// 2、使用map转变数据结构
val res = filter.map(_.asInstanceOf[Int] * 2)
println(res)
使用偏函数
// 使用偏函数
val res = list.collect {
case x: Int => x * 2 // 使用模式匹配
}
println(res)
所以在一些特殊的场景下使用偏函数更加方便快捷