Swift 隐藏宝藏:“逆天改命”调整方法重载(function overloading)优先级

news2024/11/19 10:17:21

在这里插入图片描述

概览

在 Swift 语言中有很多隐藏“宝藏”悄悄深埋在不为人知的角落,静静等待着有缘秃头码农们的大力挖掘。

在这里插入图片描述

而在这里,我们将介绍 Swift 语言中一个非常有用的秘技:方法重载优先级判断以及如何改变它。

在本篇博文中,您将学到如下内容:

  • 概览
  • 1. 什么是方法重载(function overloading)?
  • 2. Swift 中方法重载优先级判断原则
  • 3. 改变游戏规则!
  • 总结

相信学完本课后,小伙伴们一定会对 Swift 语言的博大精深所折服,并将本课学到的这一隐秘技能发扬光大!

那还等什么呢?让我们马上开始宝藏的深入挖掘之旅吧!

Let‘s Go!!!😉


本篇博文对应的视频课,欢迎观赏:

Swift 趣味开发之如何“逆天改命”调整方法重载优先级


1. 什么是方法重载(function overloading)?

方法重载(function overloading)是很多开发语言都支持的一种特性,它被用来多样化同名方法或函数的调用。使用方法重载可以大大增加同名方法或函数调用的灵活性。

比如,在以下代码中三个 test 函数互为重载:

func test() {
    print(#function)
}

func test(value: Int) {
    print(#function)
}

func test(value: Int, needChanged: Bool) {
    print(#function)
}

方法重载的一般要求为方法名相同,但方法签名会有所不同。值得说明的是,只考虑签名中的返回类型在某些情况下会产生模棱两可的语义。

func test() {
    print(#function)
}

func test() -> String {
    print(#function)
    return "test"
}

/* 直接调用 test() 会产生歧义!
error: Test.playground:13:1: error: ambiguous use of 'test()'
*/
test()

如上代码所示,如果只有方法返回类型不同则会让编译器“不知所措”,我们必须显式告诉编译器我们的“精确”意图:

// 会调用返回 String 版本的 test() 方法
let text: String = test()

注意,不要将方法重载和方法重写(overriding)相混淆:后者被用来支持对象中相同方法的多态性;前者在编译时被考虑,后者则在运行时被考虑。

2. Swift 中方法重载优先级判断原则

上面我们了解了 Swift 方法重载的不同形式。那么,对于名称相同的方法来说,如果在调用时满足其中多个重载语义,那么到底实际会使用哪个重载方法呢?

func test() {
    print(#function)
}

func test(value: Int = 11) {
    print(#function)
}

// 实际会调用上面哪个重载方法呢?
test()

如上例所示,我们创建了名为 test 的两个重载方法,如果我们进行 test() 调用,到底会执行上面哪个方法呢?

前 Swift 核心组成员 Jordan Rose 曾在不经意间透露过解决这种情况的“秘诀”:

The general principle is that the most specific overload should win.

那就是:具体胜过一般原则!

这意味着,当方法的多个重载同时满足调用语义时,越具体的重载越会被优先考虑;约束条件越少的重载越会被优先考虑。

func test() {}
func test(value: Int = 11) {}

还拿上面的例子来说,对于 test() 语义来说,第一个方法会被调用,因为它不需要假设用户选择了默认参数,约束条件更少。

类似的,对于下面的例子,由于不需要假设用户在调用时选择单个参数 test 方法的不定参数重载版本,所以实际 test() 采用的是 test(_ value: Int) 这一约束更少、更简单的重载调用:

func test(_ value: Int) {
    print(#function)
}

func test(_ values: Int...) {
    print("不定参数(Variadic):\(#function)")
}

// 会调用第一个方法重载
test(11)

同理,如果非要在普通重载和泛型重载中选择一个的话,编译器将会毫不犹豫的选择前者:

func test(_ value: Int) {
    print(#function)
}

func test<N: Numeric>(_ value: N) {
    print("泛型:\(#function)")
}

// 将会调用非泛型版本的重载
test(11)

俗话说得好:“我命由我不由天”!小伙伴们的疑问是:我们能不能改变编译器对于多个重载版本的选择偏好呢?

答案是肯定的!

3. 改变游戏规则!

在某些情况下,我们希望让本该“不受人待见”的重载方法重新“翻身做主人”。比如,对于之前泛型重载的那个例子,如果我们希望泛型版本的重载优先被调用,该如何是好呢?

func test(_ value: Int) {
    print(#function)
}

func test<N: Numeric>(_ value: N) {
    print("泛型:\(#function)")
}

// 如果希望调用泛型版本的重载,该如何是好?
test(11)

在 Swift 语言中,幕后秃头大佬们提供了一种机制,让我们可以“降低”某一种方法重载的“偏爱程度”。这可以通过在其方法定义前增加 @_disfavoredOverload 修饰符来搞定:

@_disfavoredOverload
func test(_ value: Int) {
    print(#function)
}

func test<N: Numeric>(_ value: N) {
    print("泛型:\(#function)")
}

// 现在会调用泛型版本的重载方法
test(11)

如上代码所示,我们向编译器挑明了小伙伴们更“讨厌”非泛型版本重载的强烈情感,所以编译器会非常知趣的选择泛型版本的重载调用。

最后再举一个“栗子”。对于以下 3 种 test() 方法的重载来说,默认会选择第一种重载;当第一种重载被 @_disfavoredOverload 修饰后,才会选择第二种重载;只有当前两种重载都被“嫌弃”之后,才轮到最后的泛型重载闪亮登场:

@_disfavoredOverload
func test(_ value: Int) {
    print(#function)
}

@_disfavoredOverload
func test(_ values: Int...) {
    print("不定参数(Variadic):\(#function)")
}

func test<N: Numeric>(_ value: N) {
    print("泛型:\(#function)")
}

// 只有前两种重载都被“嫌弃”之后,才轮到最后一种重载!
test(11)

现在,小伙伴们对于 Swift 语言中多个重载方法到底该选谁?以及如何进一步“暗箱操作,逆天改命”修改默认重载规则的方法都了然于胸了吧!棒棒哒!💯


@_disfavoredOverload 修饰符前面有下划线,这意味着它是 Swift 语言的一个内部特性,在将来很可能会被丢弃,所以如果大家依赖于它则需要特别留意。

所幸的是,在最新 Swift 5.9 中 @_disfavoredOverload 仍然可用。


总结

在本篇博文中,我们先是介绍了 Swift 语言中当方法的多个重载同时满足调用语义时编译器的选择之道,并且随后进一步讨论了如何“逆天改命”修改这一默认的选择法则。

感谢观赏,再会!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1442897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

巴尔加瓦算法图解:算法运用(上)

目录 树反向索引傅立叶变换 并行算法MapReduce函数 树 如果能将用户名插入到数组的正确位置就好了&#xff0c;这样就无需在插入后再排序。为此&#xff0c;有人设计了一种名为二叉查找树(binary search tree)的数据结构。 每个node的children 都不大于两个。对于其中的每个…

7点原因,解密可视化大屏为啥要3D效果

真实感&#xff1a; 3D效果可以让用户感受到更真实的视觉效果&#xff0c;让用户更加身临其境&#xff0c;增强用户的参与感和沉浸感。 立体感&#xff1a; 3D效果可以给用户带来更强的立体感&#xff0c;让用户更加容易理解和感知物体的形状和大小。 美观性&#xff1a; 3D…

Android13多媒体框架概览

Android13多媒体框架概览 Android 多媒体框架 Android 多媒体框架旨在为 Java 服务提供可靠的接口。它是一个系统&#xff0c;包括多媒体应用程序、框架、OpenCore 引擎、音频/视频/输入的硬件设备&#xff0c;输出设备以及一些核心动态库&#xff0c;比如 libmedia、libmedi…

【OrangePi Zero2 智能家居】阿里云人脸识别方案

一、接入阿里云 二、C语言调用阿里云人脸识别接口 三、System V消息队列和POSIX 消息队列 一、接入阿里云 在之前树莓派的人脸识别方案采用了翔云平台的方案去1V1上传比对两张人脸比对&#xff0c;这种方案是可行&#xff0c;可 以继续采用。但为了接触更多了云平台方案&…

8种基本类型的包装类(与String的转换)

java针对8种基本数据类型&#xff0c;定义了相应的引用类型&#xff1a;包装类(封装类)&#xff0c;有了类的特点&#xff0c;就能调用类中的方法&#xff0c;java才是真正的面向对象。 基本数据类型 包装类byte Byteshort Shortint Integerlong Longfloat Floa…

Infuse通过Alist添加115网盘资源

说明 通过Alist代理管理115网盘&#xff0c;Infuse再添加Alist代理的115网盘的WebDAV 准备一台Linux服务器安装Alist 我这里用的华为云CentOS7&#xff0c;使用Docker容器 安装Alist docker run -d --restartalways -v /etc/alist:/opt/alist/data -p 5244:5244 -e PUID0 …

SegmentAnything官网demo使用vue+python实现

一、效果&准备工作 1.效果 没啥好说的&#xff0c;低质量复刻SAM官网 https://segment-anything.com/ 需要提一点&#xff1a;所有生成embedding和mask的操作都是python后端做的&#xff0c;计算mask不是onnxruntime-web实现的&#xff0c;前端只负责了把rle编码的mask解…

[架构之路-275]:五张图向你展现软件开发不仅仅是编码,而是一个庞大的系统工程

目录 一、软件开发是组织架构的一部分&#xff0c;是为业务服务的 二、软件开发是一个系统工程&#xff0c;需要组织各种组织内的资源 三、目标软件是一个复杂的系统 四、软件开发过程本身是一个系统工程 五、目标软件的测试验证是一个系统工程 一、软件开发是组织架构的一…

MYSQL笔记:约束条件

MYSQL笔记&#xff1a;约束条件 主键约束 不能为空&#xff0c;值必须是不同的&#xff08;唯一性&#xff09; 一个表只能修饰一个主键 PRIMARY KEY自增约束 AUTO_INCREMENT唯一键约束 可以为空 unique非空约束 not null 默认值约束 default 外键约束 foreign key …

基于图像掩膜和深度学习的花生豆分拣(附源码)

目录 项目介绍 图像分类网络构建 处理花生豆图片完成预测 项目介绍 这是一个使用图像掩膜技术和深度学习技术实现的一个花生豆分拣系统 我们有大量的花生豆图片&#xff0c;并以及打好了标签&#xff0c;可以看一下目录结构和几张具体的图片 同时我们也有几张大的图片&…

Qt网络编程-ZMQ的使用

不同主机或者相同主机中不同进程之间可以借助网络通信相互进行数据交互&#xff0c;网络通信实现了进程之间的通信。比如两个进程之间需要借助UDP进行单播通信&#xff0c;则双方需要知道对方的IP和端口&#xff0c;假设两者不在同一主机中&#xff0c;如下示意图&#xff1a; …

【C语言】SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)

一、SYSCALL_DEFINE3与系统调用 在Linux操作系统中&#xff0c;为了从用户空间跳转到内核空间执行特定的内核级操作&#xff0c;使用了一种机制叫做"系统调用"&#xff08;System Call&#xff09;。系统调用是操作系统提供给程序员访问和使用内核功能的接口。例如&…

OnlyOffice-8.0版本深度测评

OnlyOffice 是一套全面的开源办公协作软件&#xff0c;不断演进的 OnlyOffice 8.0 版本为用户带来了一系列引人瞩目的新特性和功能改进。OnlyOffice 8.0 版本在功能丰富性、安全性和用户友好性上都有显著提升&#xff0c;为用户提供了更为强大、便捷和安全的文档处理和协作环境…

【Docker】02 镜像管理

文章目录 一、Images镜像二、管理操作2.1 搜索镜像2.1.1 命令行搜索2.1.2 页面搜索2.1.3 搜索条件 2.2 下载镜像2.3 查看本地镜像2.3.1 docker images2.3.2 --help2.3.3 repository name2.3.4 --filter2.3.5 -q2.3.6 --format 2.4 给镜像打标签2.5 推送镜像2.6 删除镜像2.7 导出…

React18原理: 渲染与更新时的重点关注事项

概述 react 在渲染过程中要做很多事情&#xff0c;所以不可能直接通过初始元素直接渲染还需要一个东西&#xff0c;就是虚拟节点&#xff0c;暂不涉及React Fiber的概念&#xff0c;将vDom树和Fiber 树统称为虚拟节点有了初始元素后&#xff0c;React 就会根据初始元素和其他可…

1g的视频怎么压缩到200m?3个步骤解决~

把1G的文件压缩到200M&#xff0c;可以有效节省存储空间&#xff0c;加快传输速度&#xff0c;在某些情况下&#xff0c;压缩文件可以提供更好的安全性&#xff0c;例如通过加密或压缩算法保护文件内容。下面就向大家介绍3个好用的方法。 方法一&#xff1a;使用嗨格式压缩大师…

立体感十足的地图组件,如何设计出来的?

以下是一些设计可视化界面中的地图组件更具备立体感的建议&#xff1a; 使用渐变色&#xff1a; 可以使用不同的渐变色来表现地图的高低差异&#xff0c;例如使用深蓝色或深紫色来表示海底&#xff0c;使用浅绿色或黄色来表示低地&#xff0c;使用橙色或红色来表示高地。 添加…

springboot173疫苗发布和接种预约系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

数据分析基础之《pandas(7)—高级处理2》

四、合并 如果数据由多张表组成&#xff0c;那么有时候需要将不同的内容合并在一起分析 1、先回忆下numpy中如何合并 水平拼接 np.hstack() 竖直拼接 np.vstack() 两个都能实现 np.concatenate((a, b), axis) 2、pd.concat([data1, data2], axis1) 按照行或者列…

[超分辨率重建]ESRGAN算法训练自己的数据集过程

一、下载数据集及项目包 1. 数据集 1.1 文件夹框架的介绍&#xff0c;如下图所示&#xff1a;主要有train和val&#xff0c;分别有高清&#xff08;HR&#xff09;和低清&#xff08;LR&#xff09;的图像。 1.2 原图先通过分割尺寸的脚本先将数据集图片处理成两个相同的图像…