Swift 入门之自定义类型的模式匹配(Pattern Matching)

概览
小伙伴们都知道 Swift 是一门简洁、类型安全、极富表现力以及“性感迷人”的编程语言。
和大多数语言一样,在 Swift 中也有一些隐藏着的、不为人知的宝藏特性。利用它们我们可以极大增加撸码的愉悦和成就感。
其中,模式匹配(Pattern Matching)便是如此!征服它,我们的 Swift 开发技能又可以大步迈上一个新的台阶。
在本篇博文中,您将学到以下内容:
- 概览
- 1. 什么是模式匹配?
- 2. 模式匹配符
- 3. 模式匹配在 switch 语句中的应用
- 4. 威力大增:模式匹配重载
- 总结
闲言少叙,让我们马上开始模式匹配的探索之旅吧!
Let’s Go!!!😉
本篇博文对应的视频课,欢迎小伙伴们恣意观赏:
Swift趣味开发征服模式匹配(Pattern Match)
- 哔哩哔哩 bilibili
1. 什么是模式匹配?
模式匹配是一种让我们可以更简洁更便利的比较、检查和解析数据的方式。
不光在 Swift 语言中,模式匹配的概念在很多其它编程语言中都能大放异彩。
比如,在下面 ruby 代码中我们通过模式匹配快速的检查了正则表达式是否匹配指定的字符串:
irb(main):001:0> r = /[a-z]at/
=> /[a-z]at/irb(main):002:0> r =~ "xat"
=> 0
irb(main):003:0> r =~ "11zat"
=> 2
irb(main):004:0> r =~ "1at"
=> nil
在 Swift 中的模式匹配与此类似,不过它们特别适用于 switch 语句的语境中。
那么 switch 语句如何适配模式匹配呢?答案是:用模式匹配符。
2. 模式匹配符
在 Swift 语言中,模式匹配符为 ~=。在内置一些类型上它会退化为 == 操作符的行为:
let string = "hello"
let power = 11if string ~= "hello", power ~= 11 {print("matched!")
}
/* 输出结果为:
matched!
*/
注意,Swift 中匹配符(~=)与 ruby 中(=~)是正好反过来的。
我们可以为任意自定义类型做匹配模式的适配:
struct Foo {static func ~=(pattern: Double, value: Foo) -> Bool {value.size == pattern}var size = CGFloat.zero
}let foo = Foo()
if 0.0 ~= foo {print("matched!")
}
/*
输出结果为:
matched!
*/
这里有两点需要注意:
- 匹配模式方法可以定义在类型外面;
- 若还要做“逆向”匹配,则我们需要两个匹配方法;
以下是演示代码:
struct Foo {var size = CGFloat.zero
}func ~=(pattern: Double, value: Foo) -> Bool {value.size == pattern
}// 逆向匹配方法
func ~=(value: Foo, pattern: CGFloat) -> Bool {value.size == pattern
}let foo = Foo()
if 0.0 ~= foo {print("matched!")
}// 逆向匹配
if foo ~= 0.0 {print("matched too!")
}
/*输出结果为:
matched!
matched too!
*/
我们还可以对 Swift 标准库中的类型做扩展以支持匹配模式,比如让正则表达式支持 ~= 操作符:
let regex = /[a-z]at/func ~=(pattern: String, value: Regex<Substring>) -> Bool {let result = try? pattern.firstMatch(of: value)return result != nil
}if "11xat" ~= regex {print("matched!")
}
/*输出结果为:
matched!
*/
直接利用 ~= 匹配可以为我们开发带来一定便利,不过更好的 idea 是将其嵌入到 switch 语句中以发挥最大威力。
3. 模式匹配在 switch 语句中的应用
在 Swift 中 switch 语句背后那个“默默无闻的男人”恰好就是模式匹配操作符。
struct Foo {var size = CGFloat.zero
}func ~=(pattern: Double, value: Foo) -> Bool {value.size == pattern
}
对于上面已经抱上模式匹配大腿的 Foo 类型,我们可以直接将其融入到 switch 语句中去:
let foo = Foo()switch(foo) {
case 0:print("ZERO")
case 5:print("FIVE")
default:print("others")
}
/*输出结果:
ZERO
*/
4. 威力大增:模式匹配重载
如果小伙伴们以为这就结束了,那显然大家的格局还要再打开一些。
利用重载机制,我们可以让自定义类型在 switch 语句中的模式匹配更加大放异彩。
比如,如果除了直接比较 Foo#size 属性以外,我们还想判断该属性的值是否在一个范围中,这该如何是好呢?
很简单,我们对模式匹配符进行重载:
func ~=(pattern: ClosedRange<CGFloat>, value: Foo) -> Bool {pattern.contains(value.size)
}
有了上面的定义,现在我们可以在同一个 switch 语句中用两种方式来匹配 Foo 对象的值了:
let foo = Foo(size: 11)switch(foo) {
case 0:print("ZERO")
case 5:print("FIVE")
case 0...11:print("Bingooo!!!")
default:print("others")
}/* 输出结果为:
Bingooo!!!
*/
看到这里,小伙伴们是否都已摩拳擦掌,想在 Swift 中去尝试应用模式匹配更多的“奇思妙想”呢?
勇敢去爱,不畏将来,不念过往。
放手去爱,让爱如风般自由,如光般璀璨。
所以,勇敢的去吧!The brave are invincible!棒棒哒!💯
总结
在本篇博文中,我们讨论了在 Swift 中如何优雅的适配模式匹配,并介绍了如何使用模式匹配操作符重载机制在 switch 语境中让开发“简约而简单”。
感谢观赏,再会!😎
相关文章:
Swift 入门之自定义类型的模式匹配(Pattern Matching)
概览 小伙伴们都知道 Swift 是一门简洁、类型安全、极富表现力以及“性感迷人”的编程语言。 和大多数语言一样,在 Swift 中也有一些隐藏着的、不为人知的宝藏特性。利用它们我们可以极大增加撸码的愉悦和成就感。 其中,模式匹配(Pattern …...
MySQL-----DML基础操作
DML语句 DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增删改操作。 ▶ 添加数据(INSERT) 【语法】 1. 给指定字段添加数据 INSERTO 表名 (字段名1,字段名2,...) VALUES (值1,值2,...); 2.给全…...
提前祝大家新年好!来看看社区 2023 都得了哪些奖吧
大噶好!转眼马上就是“龙”历新年啦,不知道大家这周的工作热情怎么样呢?小陈的心已经在殷切期盼回家过年了~ RTE 开发者社区预祝诸位: 2024 年 🐲龙年添财气,万事皆胜意! 回顾过去…...
Redis核心技术与实战【学习笔记】 - 19.Pika:基于SSD实现大容量“Redis”
前言 随着业务数据的增加(比如电商业务中,随着用户规模和商品数量的增加),就需要 Redis 能保存更多的数据。你可能会想到使用 Redis 切片集群,把数据分散保存到不同的实例上。但是这样做的话,如果要保存的…...
qt-C++笔记之contains()和isEmpty()函数、以及部分其他函数列举
qt-C笔记之contains()和isEmpty()函数、以及部分其他函数列举 code review! 文章目录 qt-C笔记之contains()和isEmpty()函数、以及部分其他函数列举contains()isEmpty() 类似的其他函数列举通用容器类函数字符串特有函数 在Qt C开发中, contains() 和 isEmpty()…...
极速搭建幻兽帕鲁私服,叫上好友春节假期一起联机畅玩帕鲁
文章目录 前言幻兽帕鲁私服详细部署教程查看服务器开始游戏自定义游戏参数配置 前言 行业资讯 《幻兽帕鲁》的火爆对开发商 Pocketpair 来说,代价是巨大的。该游戏的成功让首席执行官沟部拓郎最近在推特上表示,他可能因服务器运营费用而面临破产。据他透…...
MagicVideo-V2:多阶段高保真视频生成框架
本项工作介绍了MagicVideo-V2,将文本到图像模型、视频运动生成器、参考图像embedding模块和帧内插模块集成到端到端的视频生成流程中。由于这些架构设计的好处,MagicVideo-V2能够生成具有极高保真度和流畅度的美观高分辨率视频。通过大规模用户评估&…...
【三】【C++】类与对象(二)
类的六个默认成员函数 在C中,有六个默认成员函数,它们是编译器在需要的情况下自动生成的成员函数,如果你不显式地定义它们,编译器会自动提供默认实现。这些默认成员函数包括: 默认构造函数 (Default Constructor)&…...
ffmpeg 输入文件,输入出udp-ts 指定pid
要使用FFmpeg将输入文件转换为UDP传输流(TS)并指定特定的PID,您可以使用以下命令: ffmpeg -i input_file -c:v libx264 -preset ultrafast -tune zerolatency -f mpegts -map 0:v:0 -map 0:a:0 -pid 0x12345678 udp://output_addr…...
自研人工智能小工具-小蜜蜂(国外ChatGpt的平替)
国内有非常多好用的人工智能工具,但均无法完全替代国外ChatGpt。 ChatGPT相较于其他国内工具的优势在于以下几点: 创新的语言生成能力:ChatGPT是由OpenAI开发的先进的自然语言生成模型,它采用了大规模的预训练和精细调整方法。因此…...
Stable Diffusion 模型下载:ReV Animated
模型介绍 该模型能够创建 2.5D 类图像生成。此模型是检查点合并,这意味着它是其他模型的产物,以创建从原始模型派生的产品。 条目内容类型大模型基础模型SD 1.5来源CIVITAI作者s6yx文件名称revAnimated_v122EOL.safetensors文件大小5.13GB 生成案例 …...
某赛通电子文档安全管理系统 PolicyAjax SQL注入漏洞复现
0x01 产品简介 某赛通电子文档安全管理系统(简称:CDG)是一款电子文档安全加密软件,该系统利用驱动层透明加密技术,通过对电子文档的加密保护,防止内部员工泄密和外部人员非法窃取企业核心重要数据资产,对电子文档进行全生命周期防护,系统具有透明加密、主动加密、智能…...
Prometheus 采集Oracle监控数据
前言 oracledb_exporter是一个开源的Prometheus Exporter,用于从Oracle数据库中收集关键指标并将其暴露给Prometheus进行监控和告警。它可以将Oracle数据库的性能指标转换为Prometheus所需的格式,并提供一些默认的查询和指标。 download Oracle Oracle Windows Install …...
【ARM Trace32(劳特巴赫) 使用介绍 3.1 -- 不 attach core 直接访问 memory】
文章目录 背景介绍背景介绍 在使用 trace32 时在有些场景需要不 attach core 然后去读写 memory,比如在某些情况下 core 已经挂死连接不上了,这个时候需要dump内存,这个时候需要怎做呢? print "test for memory access directly";SYStem.OPTION WAITRESET OF…...
MySQL事务和SQL优化
目录 一、什么是事务 二、事务的特征 三、MySQL使用事务 3.1 实现流程: 实现截图: 3.2 实例演示: 四、事务的隔离级别 幻读: 如何解决: 脏读: 不可重复读: 幻读和不可重复读两者区别…...
[C语言]结构体初识
结构体定义 结构体是一些值的集合,被成为成员变量,结构的每个成员可以是不同类型的变量 声明: 定义了一个结构体比如以张蓝图,不占据内存,当你创建了一个结构体变量时,才占空间. #include<stdio.h>//struct 为结构体关键字, student 自定义结构体名称 struct student …...
跨平台开发:浅析uni-app及其他主流APP开发方式
随着智能手机的普及,移动应用程序(APP)的需求不断增长。开发一款优秀的APP,不仅需要考虑功能和用户体验,还需要选择一种适合的开发方式。随着技术的发展,目前有多种主流的APP开发方式可供选择,其…...
MyBatis常见面试题汇总
说一下MyBatis执行流程? MyBatis是一款优秀的基于Java的持久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接等的过程,MyBatis的执行流程如下: 加载配…...
juc并发线程学习笔记(一)
本系列会更新我在学习juc时的笔记和自己的一些思想记录。如有问题欢迎联系。 并发编程 进程与线程 1.进程和线程的概念 程序是静态的,进程是动态的 进程 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载…...
力扣热门100题刷题笔记 - 3.无重复字符的最长子串
力扣热门100题 - 3.无重复字符的最长子串 题目链接:3. 无重复字符的最长子串 题目描述: 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。示例: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
