当前位置: 首页 > news >正文

Scala的模式匹配

Scala的模式匹配

Scala 中的模式匹配类似于Java 中的 switch 语法:下面是java中switch代码:

int i = 10
switch (i) {case 10 :System.out.println("10");break;
case 20 :System.out.println("20");break;
default :System.out.println("other number");break;
}

但是 scala 从语法中补充了更多的功能,所以更加强大。

基本语法

模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支,类似于 Java 中 default 语句。

object Test_PatternMatchBase {def main(args: Array[String]): Unit = {// 1. 基本定义语法val x: Int = 5val y: String = x match {case 1 => "one"case 2 => "two"case 3 => "three"case _ => "other"}println(y)// 2. 示例:用模式匹配实现简单二元运算val a = 25val b = 13def matchDualOp(op: Char): Int = op match {case '+' => a + bcase '-' => a - bcase '*' => a * bcase '/' => a / bcase '%' => a % bcase _ => -1}println(matchDualOp('+'))println(matchDualOp('/'))println(matchDualOp('\\'))println("=========================")// 3. 模式守卫// 求一个整数的绝对值def abs(num: Int): Int = {num match {case i if i >= 0 => icase i if i < 0 => -i}}println(abs(67))println(abs(0))println(abs(-24))}
}
  • 说明
    (1) 如果所有 case 都不匹配,那么会执行 case _ 分支,类似于 Java 中 default 语句,若此时没有case _ 分支,那么会抛出MatchError。
    (2) 每个case 中,不需要使用break 语句,自动中断case。
    (3) match case 语句可以匹配任何类型,而不只是字面量。
    (4) => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。
    在 Scala 中,模式匹配(Pattern matching)是一种强大的特性,用于对数据进行分析和处理。它可以在一个表达式中确定一个值是否匹配了某个模式,并且在匹配成功时执行相应的代码块。模式匹配可以应用于各种类型的对象,包括整数、字符、字符串、列表等。

模式匹配基本使用示例

Scala 的模式匹配语法类似于 switch 语句,但更加强大和灵活。以下是一些基本的模式匹配示例:

val x: Any = 123x match {case i: Int => println("整数:" + i)case s: String => println("字符串:" + s)case d: Double => println("双精度浮点数:" + d)case _ => println("未知类型")
}

在上面的代码中,我们将一个任意类型的值 x 进行了模式匹配。首先,我们使用 case i: Int => 匹配整数类型并将其赋值给变量 i,然后执行 println("整数:" + i) 输出整数。接着,我们使用 case s: String => 匹配字符串类型,并输出对应的信息。最后,我们使用 _ 表示其他所有类型并输出 “未知类型”。

除了基本类型之外,模式匹配还支持对列表、元组等复杂类型进行匹配,例如:

def sum(lst: List[Int]) : Int = lst match {case Nil => 0case x :: tail => x + sum(tail)
}println(sum(List(1, 2, 3))) // 输出 6

在上面的代码中,我们定义了一个 sum 函数用于计算列表中所有整数的和。在函数内部,我们使用模式匹配来处理两种情况:当列表为空时(case Nil => 0),返回 0;否则,我们使用 case x :: tail => 匹配列表的头部元素 x 和剩余元素 tail,并递归地调用 sum(tail) 来计算剩余元素的和,并将其与头部元素 x 相加。

需要注意的是,在模式匹配中,每个匹配分支都必须满足类型一致性和互斥性,以避免出现匹配二义性的情况。

模式守卫

  1. 说明
    如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。
  2. 代码示例
object TestMatchGuard {
def main(args: Array[String]): Unit = {//求一个整数的绝对值
def abs(x: Int) = x match {
case i: Int if i >= 0 => i
case j: Int if j < 0 => -j
case _ => "type illegal"
}
println(abs(-5))
}
}

模式匹配类型

在 Scala 中,模式匹配非常灵活,可以在各种情况下使用。以下是一些常见的模式匹配运用情况示例:

匹配基本类型和常量值

val x: Any = 123x match {case 0 => println("匹配到 0")case 1 | 2 => println("匹配到 1 或 2")case i: Int if i > 100 => println("匹配到大于 100 的整数")case _ => println("未匹配到")
}

匹配元组

val tuple: (String, Int) = ("Scala", 3)tuple match {case ("Java", _) => println("第一个元素是 Java")case (str, num) if num > 0 => println(s"第一个元素是 $str,第二个元素是正整数")case _ => println("未匹配到")
}

匹配列表List

val list: List[Int] = List(1, 2, 3)list match {case Nil => println("空列表")case head :: tail => println(s"头部元素是 $head,剩余元素是 $tail")
}

匹配类和对象

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
case object UnknownShape extends Shapeval shape: Shape = Circle(3.0)shape match {case Circle(r) => println(s"圆形,半径是 $r")case Rectangle(w, h) => println(s"矩形,宽度是 $w,高度是 $h")case UnknownShape => println("未知形状")
}

使用模式守卫进行更复杂的匹配

val x: Any = List(1, 2, 3)x match {case list: List[_] if list.nonEmpty => println("非空列表")case list: List[_] if list.isEmpty => println("空列表")case str: String if str.length > 10 => println("字符串长度大于 10")case _ => println("未匹配到")
}

匹配数组

在 Scala 中,匹配数组与匹配列表的方式类似。你可以使用模式匹配对数组进行处理。以下是一个示例:

val array: Array[Int] = Array(1, 2, 3)array match {case Array() => println("空数组")case Array(1) => println("单个元素数组")case Array(1, 2, _*) => println("以1和2开头的数组")case Array(_, _, 3) => println("以3结尾的数组")case _ => println("未匹配到")
}

在上面的代码中,我们匹配了不同类型的数组情况。首先,使用 case Array() 匹配空数组;然后,使用 case Array(1) 匹配只包含一个元素的数组;接着,使用 case Array(1, 2, _*) 匹配以 1 和 2 开头的任意长度的数组;最后,使用 case Array(_, _, 3) 匹配以 3 结尾的数组。如果没有匹配到任何情况,就会执行最后一个 case 分支。

需要注意的是,在匹配可变长度的数组时,我们使用了 _* 表示任意长度的数组片段。

变量声明中的模式匹配

在 Scala 中,可以在变量声明中使用模式匹配来提取和赋值变量的值。这种方式被称为模式匹配的变量声明或解构赋值。以下是一个示例:

val tuple: (String, Int) = ("Scala", 3)val (str, num) = tupleprintln(s"字符串:$str")
println(s"整数:$num")

在上面的代码中,我们声明了一个元组 tuple,包含两个元素:一个字符串和一个整数。然后,我们使用模式匹配的方式将元组中的值解构并赋给了两个新的变量 strnum。这样,我们就可以通过这两个变量来访问元组中的值。

除了元组,还可以在变量声明中匹配其他数据结构,比如列表、数组等。示例如下:

val list: List[String] = List("Hello", "World")val head :: tail = listprintln(s"头部元素:$head")
println(s"剩余元素:$tail")

在上面的代码中,我们声明了一个列表 list,包含两个字符串元素。然后,使用模式匹配的变量声明方式将列表的头部元素赋给变量 head,剩余元素赋给变量 tail。这样,我们就可以分别访问列表的头部元素和剩余元素。

需要注意的是,模式匹配的变量声明在匹配失败时会抛出 MatchError 异常。为了避免这种情况,请确保变量声明与待解构的数据结构具有相同的结构和类型。

匹配对象及样例类

在 Scala 中,可以使用模式匹配来匹配各种类型的对象,包括普通类和样例类。其中,样例类是一种特殊的类,它专门用于模式匹配,因为编译器会自动生成带有模式匹配相关方法的代码。以下是一个示例:

sealed trait Fruit
case class Apple(color: String) extends Fruit
case class Banana(length: Int) extends Fruit
case object UnknownFruit extends Fruitval fruit: Fruit = Apple("red")fruit match {case Apple("red") => println("红色苹果")case Banana(len) if len > 10 => println("长度大于 10 的香蕉")case UnknownFruit => println("未知水果")case _ => println("其他水果")
}

在上面的代码中,我们定义了一个 Fruit 样例类及两个子类 AppleBanana,还有一个对象 UnknownFruit。然后,我们创建了一个 Apple 对象并将其赋给 fruit 变量。接着,使用 match 关键字来匹配不同类型的 Fruit 对象,分别输出相应的提示信息。

需要注意的是,当匹配样例类时,可以使用模式匹配提取出样例类中的属性值,并对其进行比较。在上面的代码中,使用 case Apple("red") 匹配颜色为红色的苹果。

嵌套模式匹配

当数据结构较为复杂时,可以使用嵌套的模式匹配来逐级解构和匹配。

sealed trait Location
case class City(name: String) extends Location
case class Country(name: String, capital: City) extends Locationdef printCapital(location: Location): Unit = {location match {case Country(_, City(capital)) => println(s"首都是$capital")case _ => println("未知位置")}
}

在上面的代码中,我们定义了一个 Location 类及其两个子类 City 和 Country。Country 类包含一个 City 类的实例作为首都。通过嵌套的模式匹配,我们可以提取和打印出国家的首都。

相关文章:

Scala的模式匹配

Scala的模式匹配 Scala 中的模式匹配类似于Java 中的 switch 语法&#xff1a;下面是java中switch代码&#xff1a; int i 10 switch (i) {case 10 :System.out.println("10");break; case 20 :System.out.println("20");break; default :System.out.pr…...

HttPClient简介及示例:学习如何与Web服务器进行通信

文章目录 前言一、引入依赖二、使用步骤1.创建被调用者2.创建调用者三、结果被调用者服务&#xff1a;调用者服务&#xff1a; 总结 前言 欢迎来到本篇博客&#xff0c;这是一个关于HttPClient的入门案例的指南。&#x1f389; 在今天的网络世界中&#xff0c;与服务器进行数据…...

STS4 New 安装Spring Bean Configuration File

背景介绍 在创建spring项目后&#xff0c;如果想想创建spring bean Configuration的时候&#xff0c;发下菜单没有这个选项&#xff0c;需要通过下载Spring Roo插件可满足该操作。 参考案例 参考地址&#xff1a; STS4 New 菜单没有Spring Bean Configuration File选项_SQZHA…...

Java经典面试题(异或运算)

不爱生姜不吃醋⭐️⭐️⭐️ &#x1f33b;如果本文有什么错误的话欢迎在评论区中指正哦&#x1f497; &#x1f33b;看完之后觉得不错的话麻烦动动小手点个赞赞吧&#x1f44d; &#x1f33b;与其明天开始&#xff0c;不如现在行动&#xff01;&#x1f4aa; &#x1f33b;大家…...

No primary or single unique constructor found for interface java.util.List

1.问题描述 前端 请求的参数 是 query形式&#xff0c; 参数在url中 报错信息&#xff1a; java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List2.解决办法 controller中的 请求方法 参数 加上 RequestParam...

C#关于WebService中File.Exists()处理远程路径的异常记录

目录 前言方案一打开网站对应的程序池的高级设置按下图步骤设置凭据重启网站若方案一未能解决&#xff0c;请继续尝试方案二&#x1f447; 方案二从控制面板进入到 凭据管理器为windows凭据添加凭据点击**Windows凭据**&#xff0c;并点击**添加Windows凭据**键入远程路径的地址…...

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章 xxl-job概述windows部署调度中心docker部署调度中心 xxl-job入门案例xxl-job分片广播热点文章定时计算思路分析具体实现热文章计算定时计算 查询文章接口改造来源Gitee xxl-job概述 windows部署调度中心 运行 xxl-job\do…...

【WebRTC---源码篇】(二:二)视频源VideoSourceBase

作用 这个类继承自VideoSourceInterface<webrtc::VideoFrame>模板类,并且可以处理webrtc::VideoFrame class VideoSourceBase : public VideoSourceInterface<webrtc::VideoFrame> 重要成员变量 struct SinkPair {SinkPair(VideoSinkInterface<webrtc::Vid…...

Linux_8_磁盘存储和文件系统

1 磁盘结构 1.1 设备文件 一切皆文件: open(),read(),write(),close() 设备文件:关联至一个设备驱动程序&#xff0c;进而能够跟与之对应硬件设备进行通信 设备号码: ​ 主设备号 major number,标识设备类型​ 次设备号 minor number,标识同一类型下的不同设备 设备类型:…...

VS + QT 封装带UI界面的DLL

一、创建编译DLL的项目 1.新建Qt Class Liabrary 2.新建项目&#xff0c;选择Qt Widgets Class 3.新建C类&#xff0c;可以在此类里面写算法函数用于调用。 4.下面是添加完Qt窗体类和C类之后的项目截图 5.修改头文件并编译 将uidemo_global.h中的ifdef内容复制到dialog.h上…...

逆向工程-架构真题(二十)

结构化程序设计采用自顶向下、逐步求精及模块化程序设计方法&#xff0c;通过&#xff08;&#xff09;三种基本控制结构可以构造出任何单入口单出口程序。 顺序、选择和嵌套顺序、分支和循环分支、并发和循环跳转、选择和并发 答案&#xff1a;B 解析&#xff1a; 结构化设…...

Zookeeper 入门

第 1 章 Zookeeper 入门 1.1概述 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生变化&#xff0c;Zookeeper就将…...

记录--前端使用a链接下载内容增加loading效果

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 问题描述&#xff1a;最近工作中出现一个需求&#xff0c;纯前端下载 Excel 数据&#xff0c;并且有的下载内容很多&#xff0c;这时需要给下载增加一个 loading 效果。 代码如下&#xff1a; // util…...

如何获取用户的ip地址

用户的 IP 地址可能会被隐藏或者修改&#xff0c;例如使用代理服务器、VPN 等工具&#xff0c;这样就无法准确获取用户的真实 IP 地址。 除了以上特殊情况&#xff0c;一般情况下 用户访问可能会经过一下链路 &#xff1a; 前端—>nginx—>网关—>服务 。 一般情况下后…...

单片机-控制按键点亮LED灯

1、按键电路图 定义四个按键引脚 1、按键按下 为 输入为低电平 2、按键不按下 IO有上拉电阻&#xff0c;为高电平 // 定义 按键的 管教 sbit KEY1 P3^1; sbit KEY2 P3^0; sbit KEY3 P3^2; sbit KEY4 P3^3; 2、LED灯电路图 LED 输出高电平为亮 // 定义LED灯 管教 sbit LED1…...

微信小程序新版隐私协议弹窗实现最新版

1. 微信小程序又双叒叕更新了 2023.08.22更新&#xff1a; 以下指南中涉及的 getPrivacySetting、onNeedPrivacyAuthorization、requirePrivacyAuthorize 等接口目前可以正常接入调试。调试说明&#xff1a; 在 2023年9月15号之前&#xff0c;在 app.json 中配置 __usePriva…...

GO语言圣经 第五章习题

练习5.1 修改findlinks代码中遍历n.FirstChild链表的部分&#xff0c;将循环调用visit&#xff0c;改成递归调用。 func visit(links []string, n *html.Node) []string {if n nil {return links}if n.Type html.ElementNode && n.Data "a" {for _, a : r…...

用kotlin 开发一个简单的多页面跳转

本文介绍一个简单的安卓应用的页面跳转例子&#xff0c;用的是kotlin。 运行时主页面是一个hello 和Jump 按钮&#xff0c;你按一下jump 按钮就转到 从页面&#xff0c;只是标识从页面。 开始建立一个简单工程&#xff0c;名为hello&#xff0c; 选择的是Empty views Activit…...

记录我的tensorrt 部署yolov8

系统 &#xff1a;ubuntu 18.04 代码 &#xff1a;GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT conda 环境 &#xff1a; GitHub - noahmr/yolov5-tensorrt: Real-time object detection with YOLOv5 and TensorRT cuda : 11.8 …...

什么是用户界面? 优漫动游

什么是用户界面&#xff1f; 用户界面(UI&#xff0c;UserInterface)也称人机界面&#xff0c;是人机交互、操作逻辑和界面表现的整体设计。每一种设计都有其对应的职业角色&#xff0c;其中&#xff0c;人机交互的设计人员叫做用户研究工程师&#xff0c;操作逻辑设计人员叫…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...