大数据——Scala 模式匹配

server/2024/10/20 16:13:02/

Scala

模式匹配

概述

  1. Scala中的模式匹配,类似于Java中switch-case结构,但是比Java中的switch-case的功能更加强大

  2. 语法结构

    scala">选项 match {case c1 => op1case c2 => op2...case _ => op
    }
    
  3. case _类似于Java中的default,当其他的所有的case都不匹配的时候,才会使用case _

  4. 在Scala中,没有break关键字,每一个case执行完成之后自动结束,不会顺延执行下一个case

  5. 案例

    scala">package com.fe.matchximport scala.io.StdInobject MatchDemo1 {def main(args: Array[String]): Unit = {// 获取符号val symbol = StdIn.readChar()// 获取数字val x = StdIn.readDouble()val y = StdIn.readDouble()// 四则运算val r = symbol match {case '+' => x + ycase '-' => x - ycase '*' => x * ycase '/' => x / ycase _ => 0}println(r)}}
    
  6. 如果没有case _,且所有的case都不匹配的时候,就会抛出MatchError

常见匹配

  1. 常量匹配:在Scala中,match-case匹配的时候,不限制元素的类型

    scala">package com.fe.matchxobject MatchDemo2 {def main(args: Array[String]): Unit = {// Scala中,match不限制元素的类型def typeOf(x: Any): Unit = x match {case 3 => println("整数")case 5.5 => println("小数")case true => println("布尔值")case "abc" => println("字符串")case _ => println("其他类型")}val t = (3, true, "abc", 5.5, 'a')t.productIterator.foreach(x => typeOf(x))}}
    
  2. 类型匹配

    scala">package com.fe.matchxobject MatchDemo3 {def main(args: Array[String]): Unit = {// 判断元组中每一个元素的类型val t = (4, 5.5, 6, true, 'a', "abc", 3.5f, 2L)def typeOf(x: Any): String = x match {case _: Int => "Int"case _: Double => "Double"case _: String => "String"case _: Long => "Long"case _: Boolean => "Boolean"case _: Char => "Char"case _ => "other type"}t.productIterator.foreach(x => println(typeOf(x)))}}
    
  3. 集合匹配

    scala">package com.fe.matchxobject MatchDemo4 {def main(args: Array[String]): Unit = {// 对列表中的元素类型进行匹配def listType(list: List[_]) = list match {case _: List[Int] => "Int"case _: List[Double] => "Double"case _ => "other type"}val list = List(2, 3, 4, 5)println(listType(list))// 对列表中的元素进行限定def listMatch(list: List[_]) = list match {case List(3) => "List(3)" // 固定匹配,就匹配这个List(3)case List(2, 4, 6) => "List(2,4,6)" // 固定匹配,就匹配这个List(2, 4, 6)case List(_, _) => "长度为2的List" // 匹配长度为2的列表case List("abc", _, _) => "列表的长度为3,第一个元素是abc" // 匹配列表的长度为3,并且第一个元素是"abc"case List("hello", _*) => "第一个元素是hello的列表" // 匹配第一个元素是"hello"的列表}val list1 = List(3)println(listMatch(list1))val list2 = List(2, 4, 6)println(listMatch(list2))val list3 = List('a', 'b')val list4 = List(3.5, 4.8)println(listMatch(list3))println(listMatch(list4))val list5 = List("abc", "hello", "hi")val list6 = List("abc", "hadoop", "Scala")println(listMatch(list5))println(listMatch(list6))val list7 = List("hello", "hi", "system")val list8 = List("hello")val list9 = List("hello", "david", "amy", "bob")println(listMatch(list7))println(listMatch(list8))println(listMatch(list9))}}
    

模式守卫

  1. 如果在进行匹配的时候,还需要指定其他条件,那么可以使用模式守卫

    scala">package com.fe.matchxobject MatchDemo5 {def main(args: Array[String]): Unit = {// 判断数字是几位数def test(n: Int) = n match {case _: Int if n < 0 => "负数"case _: Int if n < 10 => "一位数"case _ => "两位数"}println(test(5))// 列表def listMatch(list: List[Int]) = list match {case x if x.length == 3 && x.contains(5) => "case 1" // 列表长度为3,且包含数字5的列表case y if y.contains(7) => "case 2" // 列表中包含数字7}val list1 = List(3, 1, 5)val list2 = List(5, 2, 4)println(listMatch(list1))println(listMatch(list2))val list3 = List(7, 1, 3, 4)println(listMatch(list3))}}
    

函数参数匹配

  1. 案例

    scala">package com.fe.matchxobject MatchDemo6 {def main(args: Array[String]): Unit = {// toInt ===> AnyValval values: List[Any] = List(true, 1, 3.5, "25.53", -4, "35", 'a', false, -6.5)// 将列表中的所有的元素转化为整数// 如果是布尔值,那么true转化为1,false转化为0// 如果是字符串,那么就转化为对应的值val r = values.map(x => x match {case a: Double => a.toIntcase b: String => b.toDouble.toIntcase c: Char => c.toIntcase d: Boolean => if (d) 1 else 0case e: Int => e})println(r)// 对参数进行匹配,并且在这个过程中,是直接去进行了match操作,而没有进行其他操作// ({}),如果代码只有一行,()或者{}可以省略其一;如果有多行,那么只能考虑省略()//val r2 = values.map {case a: Double => a.toIntcase b: String => b.toDouble.toIntcase c: Char => c.toIntcase d: Boolean => if (d) 1 else 0case e: Int => e}println(r2)}}
    

对象匹配

  1. Scala中不只是可以对数据进行匹配,还能对对象进行匹配,到那时要求对应对应的类中必须提供了解析函数unapply

    scala">package com.fe.matchxobject MatchDemo7 {def main(args: Array[String]): Unit = {val p1 = Person("Bob", 21, "male")val p2 = Person("Amy", 22, "female")val p3 = Person("David", 22, "male")val p4 = Person("Grace", 23, "female")val p5 = Person("Henry", 21, "male")val persons = List(p1, p2, p3, p4, p5)// 对集合中数据进行操作def testList(p: Person) = p match {case Person(_, _, "female") => "女性用户" // 目标客户:女性case Person(_, 21, _) => "21岁客户群体" // 目标客户:21岁群体case _ =>}persons.foreach(x => println(testList(x)))}}class Person {var username: String = _var age: Int = _var gender: String = _
    }object Person {def apply(username: String, age: Int, gender: String): Person = {val p = new Personp.username = usernamep.age = agep.gender = genderp}// 解析函数,用于解析对象// 在Scala中,为了防止空指针异常,会考虑将结果封装成Option// 在封装Option的时候,如果值为空,对应的封装成None// 如果值不为空,封装成Somedef unapply(p: Person): Option[(String, Int, String)] = {if (p == null) Noneelse Some(p.username, p.age, p.gender)}
    }
    

样例类

  1. 样例类的声明和普通类差别不大,区别在于,在class之前添加了case

    scala">case class 类名 {}
    
  2. 样例类的普通类的区别

    1. 如果一个类被声明为样例类,那么Scala在编译的时候会自动的给这个样例类生成一个伴生对象;普通类需要手动声明伴生对象
    2. 样例类对应的伴生对象中,会自动覆盖applyunapplytoStringequalshashCode
    3. 也正因为样例类中会自动覆盖apply和unapply函数,所以可以参与模式匹配
    4. 样例类的主构造器中声明的参数默认是val修饰
  3. 案例

    scala">package com.fe.matchxobject CaseClassDemo {def main(args: Array[String]): Unit = {val s1 = Student("Bob", 10, "male", 3)val s2 = Student("Tom", 10, "male", 3)val s3 = Student("Sam", 10, "male", 3)val s4 = Student("Cam", 10, "female", 3)val s5 = Student("Amy", 10, "female", 3)val s6 = Student("Dan", 10, "male", 3)val students = List(s1, s2, s3, s4, s5, s6)for (s <- students) {val r = s match {case Student(_, _, "male", _) => "男生"case _ => "女生"}println(r)}}}// 自动给Student生成伴生对象`object Student`
    case class Student(name: String, age: Int, gender: String, grade: Int) {// 声明在类中的属性,默认不是被apply接收和unapply解析// var address:String = _
    }/*
    object Student{def apply(name: String, age: Int, gender: String, grade: Int):Student = new Student(name, age, gender, grade)def unapply(s:Student) = Some(u.name, u.age, u.gender, u.grade)}*/
    

偏函数

  1. 对于Scala的集合函数而言,分为全函数和偏函数

    1. 全函数:对集合中所有的元素进行操作,例如mapreduce
    2. 偏函数:对集合中的部分元素进行操作
  2. 案例

    scala">package com.fe.matchxobject MatchDemo8 {def main(args: Array[String]): Unit = {val list: List[Any] = List(2, 'a', 6, 3.5, true, 8, 5.21, 9, false, "abc")// 需求:将列表中的整数挑选出来,计算整数的平方形式// 方式一:过滤 -> 转化为整数 -> 计算平方val r = list.filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int]).map(x => x * x)println(r)// 方式二:偏函数val r2 = list.collect { case a: Int => a * a }println(r2)}}
    

异常机制

  1. Scala中的异常机制,类似于Java中的异常机制,但是又不完全一样。Scala中所有的异常都是在运行的时候才会检查,没有所谓的编译时异常

  2. Scala捕获异常的方式

    scala">try{代码块
    } catch {case e1:异常名 => 处理case e2:异常名 => 处理...
    } finally{代码块
    }
    
  3. 案例

    scala">package com.fe.exceptionimport scala.io.StdInobject ExceptionDemo {def main(args: Array[String]): Unit = {try {val x = StdIn.readInt()val y = StdIn.readInt()println(x / y)} catch {case e: ArithmeticException => println("捕获到一个算术异常")}}}
    
  4. 在Scala中,如果一个函数没有别的返回值,而是只抛出了一个异常,那么此时这个函数的返回值类型是Nothing

    scala">def testException():Nothing ={throw new IllegalArgumentException
    }
    
  5. Scala中提供了一个注解throws,用于标记这个函数有异常抛出。这个注解仅仅起提示作用,不要求使用者必须处理这个异常

隐式转换(implicit)

概述

  1. 当编译器对当前代码第一次编译失败的时候,会在当前的环境中查找能够让代码编译通过的方式,用于将当前的类型进行转换,进行二次编译,这个过程就称之为隐式转换
  2. 隐式转换包含隐式函数、隐式参数和隐式类
  3. Scala运行的时候,自动加载Predef类,Predef类中定义了大量的隐式转换

隐式函数

  1. 隐式函数,能够在不改变某一个类的前提下,扩展这个类的功能

  2. 案例

    scala">package com.fe.implicitxobject ImplicitDemo {def main(args: Array[String]): Unit = {// 正常情况下,x是Int类的对象,所以无法调用SumInt中的函数val x: Int = 10// 在没法改变Int类的前提下,又想扩展Int的功能// 此时,就意味着需要将Int -> SumInt对象之后才能调用// 此时可以定义一个隐式函数来完成这个转换过程// 在底层,偷偷的将Int包装成了SumIntimplicit def transform(n:Int):SumInt = new SumInt(n)println(x.sum)println(x.^(5))}}class SumInt(val n: Int) {def sum: Int = {println("我来啦~~~")var r = 0for (i <- 1 to n) r += ir}}
    

隐式参数

  1. 隐式参数,指的是在作用域中定义的可以被自动匹配的参数

  2. 注意:

    1. 同一个作用域中,相同类型的隐式参数只能有1个
    2. 编译器是根据参数类型匹配,而不是根据参数名称匹配
  3. 案例

    scala">package com.fe.implicitxobject ImplicitDemo2 {def main(args: Array[String]): Unit = {implicit val s: String = "男"// 性别默认为"男",除非用户指定为"女"// 第三个参数声明为隐式参数,所以如果调用的时候不给定,自动的在当前作用域内自动寻找同类型的隐式变量def register(username: String)(age: Int)(implicit gender: String): Unit = println(s"新注册用户$username,性别$gender,年龄$age")// 隐式参数的优先级高于默认参数def login(username: String)(implicit gender: String = "女"): Unit = println(s"用户$username,性别$gender 登陆")register("Bob")(15)register("David")(16)login("Bob")login("Any")("女")}}
    

隐式类

  1. 如果需要对某一个类产生的对象进行功能扩展,而又不想要改变原来的类,那么除了可以使用隐式函数,还可以使用隐式类

  2. 注意:隐式类不是顶级类,即隐式类不能直接定义到包中,而必须定义到类、伴生对象或者包对象中

  3. 饮食类必须提供构造器,并且构造器中只能有1个参数!

    scala">package com.fe.implicitxobject ImplicitDemo3 {def main(args: Array[String]): Unit = {val x: Int = 5println(x.fac)}implicit class FacInt(n: Int) {def fac: Int = {var r = 1for (i <- 1 to n) r *= ir}}}
    

http://www.ppmy.cn/server/18158.html

相关文章

android 上传视频

1.在页面按钮或图标控件中添加点击事件&#xff0c;并调用选择文件动作 //点击图片选择视频按钮事件public void uploadvideo(View view){Intent intent new Intent(Intent.ACTION_GET_CONTENT); // 选择文件动作intent.setType("video/*"); …

SOLIDWORKS巧手塑形:尖角转圆角——轻松掌握多种圆角处理技巧!

各位工程师在使用SOLIDWORKS设计产品时&#xff0c;圆角设计是一个不可或缺的操作。 接下来&#xff0c;就让我们了解一下SOLIDWORKS中的一些圆角设计方式。 01 二维草图圆角 二维草图圆角是非常常用的操作&#xff0c;在草图状态下绘制轮廓形状时&#xff0c;添加圆角&#xf…

Linux c++ onvif客户端开发(8):GetServices

本文是Linux c onvif客户端开发系列文章之一&#xff1a; Linux c onvif客户端开发(1): 根据wsdl生成cpp源文件Linux c onvif客户端开发(2): 获取摄像头H264/H265 RTSP地址Linux c onvif客户端开发(3): 扫描设备Linux c onvif客户端开发(4): 扫描某个设备是否支持onvifLinux c…

【React Router】快速使用

组件 index.js import React from react; import ReactDOM from react-dom/client; import App from ./App; import {BrowserRouter} from "react-router-dom";// 创建根实例 const root ReactDOM.createRoot(document.getElementById(root)); root.render(// his…

四级英语之词类的确定

在四级英语中&#xff0c;确定词类的方法主要有以下几种&#xff1a; 通过句子结构确定&#xff1a; 当空格处的前面是冠词、形容词或及物动词时&#xff0c;空格处应当要填入名词。当空格处的前面是介词时&#xff0c;空格处是充当介词宾语的&#xff0c;应当填入一个名词或者…

【数据库】MongoDB

文章目录 [toc]数据库操作查询数据库切换数据库查询当前数据库删除数据库查询数据库版本 数据集合操作创建数据集合查询数据集合删除数据集合 数据插入插入id重复的数据 数据更新数据更新一条丢失其他字段保留其他字段 数据批量更新 数据删除数据删除一条数据批量删除 数据查询…

Uniapp 点击图片放大

1、html(循环图片) <view v-for"(i,index) in photo_list" :key"photoindex"><img :src"i" alt"" click"ClickImage(photo_list,i)" /></view> 2、js(方法) ClickImage(PhotoAddress, index) {uni.previ…

【c++】vector模拟实现与深度剖析

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 vector涉及到许多细节问题&#xff0c;比如双层深拷贝&#xff0c;迭代器失效等&#xff0c;本篇文章我们通过模拟实现来深度理解这块的内容 目录 1.基本框架2.构造和销毁3.元素访问4.获取…