Scala 入门-模式匹配

2024-06-03 13:38
文章标签 入门 scala 模式匹配

本文主要是介绍Scala 入门-模式匹配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

专栏原创出处:github-源笔记文件 ,github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。

Scala 编程语言专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Scala 编程语言

什么是模式匹配

模式匹配用来检查某一个值是否适用于定义好的一个固定模式,匹配成功可以解构出该值的所有组成元素。
模式匹配是 Java 中的 switch 语句的升级版,同样可以用于替代一系列的 if/else 语句。

  • 「案例类」 非常适用于模式匹配,具体内容可以参考《案例类》。

  • 可以利用「提取器对象」中的 unapply 方法来定义非案例类对象的匹配。

语法

一个模式匹配语句包括一个待匹配的值,match 关键字,以及至少一个在 {}中包含的 case 语句。

  import scala.util.Randomval x: Int = Random.nextInt(10)// 具体值的模式匹配x match {case 0 => "zero"case 1 => "one"case 2 => "two"case _ => "other"  // 表示匹配其余所有情况,在这里就是其他可能的整型值。}// match 表达式是有返回值的,因为所有的情况均返回 string,所以 matchTest 函数的返回值类型是 stringdef matchTest(x: Int): String = x match {case 1 => "one"case 2 => "two"case _ => "other"}

匹配类型

案例类的模式匹配

Scala 会为案例类自动创建伴生对象,而伴生对象中定义了 unapply 方法。
因此案例类很适合用于模式匹配,可以通过模式匹配获取成员属性。

  abstract class Notificationcase class Email(sender: String, title: String, body: String) extends Notificationcase class SMS(caller: String, message: String) extends Notificationcase class VoiceRecording(contactName: String, link: String) extends Notificationdef showNotification(notification: Notification): String = {notification match {// 对象的 sender 和 title 属性在返回值中被使用,而 body 属性则被忽略,故使用 _ 占位符代替。case Email(sender, title, _) =>s"You got an email from $sender with title: $title"case SMS(number, message) =>s"You got an SMS from $number! Message: $message"case VoiceRecording(name, link) =>s"you received a Voice Recording from $name! Click the link to hear it: $link"}}val someSms = SMS("12345", "Are you there?")val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")println(showNotification(someSms))// You got an SMS from 12345! Message: Are you there?println(showNotification(someVoiceRecording))// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123

模式守卫

为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上 if (boolean expression)

  abstract class Notificationcase class Email(sender: String, title: String, body: String) extends Notificationcase class SMS(caller: String, message: String) extends Notificationcase class VoiceRecording(contactName: String, link: String) extends Notificationdef show(notification: Notification): String = {notification match {case Email(sender, title, _) =>s"You got an email from $sender with title: $title"case SMS(number, message) =>s"You got an SMS from $number! Message: $message"case VoiceRecording(name, link) =>s"you received a Voice Recording from $name! Click the link to hear it: $link"}}def importantShow(notification: Notification, important: Seq[String]): String = {notification match {// 此处定义的模式匹配为守卫模式,匹配成功之后还需要进行 if 判断// 只有是 Email 类型,并且 important 集合中存在 sender 属性才可以匹配成功case Email(sender, _, _) if important.contains(sender) =>"You got an email from special someone!"case SMS(number, _) if important.contains(number) =>"You got an SMS from special someone!"case other =>// nothing special, delegate to our original show functionshow(other)}}val important = Seq("867-5309", "jenny@gmail.com")val sms = SMS("867-5309", "Are you there?")val sms2 = SMS("867-5111", "I'm here! Where are you?")val voice = VoiceRecording("Tom", "voicerecording.org/id/123")println(importantShow(sms, important))// You got an SMS from special someone!println(importantShow(sms2, important))// You got an SMS from 867-5111! Message: I'm here! Where are you?println(importantShow(voice, important))// you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123

仅匹配类型

本模式匹配适用于不同类型的对象需要调用不同的方法的情况。
一般使用类型的首字母作为 case 的标识符。

{abstract class Devicecase class Phone(model: String) extends Device {def screenOff = "Turning screen off"}case class Computer(model: String) extends Device {def screenSaverOn = "Turning screen saver on..."}// goIdle 函数对不同类型的 Device 有着不同的表现,采用类型的首字母作为 case 的标识符:p、cdef goIdle(device: Device) = device match {case p: Phone => p.screenOffcase c: Computer => c.screenSaverOn}
}

中缀表达式的模式匹配

中缀表达式是一个算数逻辑公式的表示方法,将 操作符 置于 操作数 的中间。

  // 例如 :: 是 scala.collection.immutable.List 中定义的一个方法// def ::[B >: A] (x: B): List[B] = new scala.collection.immutable.::(x, this)1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)// 中缀表达式用于模式匹配List(1,2,3,4,5) match {// first 为第一个元素,second 为第二个元素,tail 为剩余元素// 即 List(1,2,3,4,5) = 1 :: 2 :: List(3,4,5)case first :: second :: tail => println(tail)}// List(3, 4, 5)

什么是密封类

「特质」 和 「类」 可以用 sealed 标记为密封的,被标记后其所有子类必须与它存在于相同的文件中,从而保证所有子类型都是已知的。
用于模式匹配,当抽象类加了 sealed 之后,scala 在编译的时候会进行检查,如果有漏掉的 case 类型,会警告提示。

  // Couch 和 Chair 必须和 Furniture 定义在相同的文件中sealed abstract class Furniturecase class Couch() extends Furniturecase class Chair() extends Furniture// 由于 Man 加了 sealed 关键字,模式匹配时,scala 会检测是否遗漏匹配的类型,编译时会警告提醒sealed abstract class Mancase object American extends Mancase object Chinese extends Mancase object Russia extends Mandef from(m: Man) = m match {case American ⇒ println("American")case Chinese ⇒ println("Chinese")}// Warning:(61, 29) match may not be exhaustive.It would fail on the following input: Russia//    def from(m: Man) = m match {// 如果确定不会有 Russia 类型的对象传入,可以使用下面的方法去掉警告提示def from(m: Man) = (m : @unchecked) match {case American ⇒ println("American")case Chinese ⇒ println("Chinese")}

这篇关于Scala 入门-模式匹配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027140

相关文章

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

Python中OpenCV与Matplotlib的图像操作入门指南

《Python中OpenCV与Matplotlib的图像操作入门指南》:本文主要介绍Python中OpenCV与Matplotlib的图像操作指南,本文通过实例代码给大家介绍的非常详细,对大家的学... 目录一、环境准备二、图像的基本操作1. 图像读取、显示与保存 使用OpenCV操作2. 像素级操作3.

POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能

《POI从入门到实战轻松完成EasyExcel使用及Excel导入导出功能》ApachePOI是一个流行的Java库,用于处理MicrosoftOffice格式文件,提供丰富API来创建、读取和修改O... 目录前言:Apache POIEasyPoiEasyExcel一、EasyExcel1.1、核心特性

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis