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

在这里插入图片描述

概览

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

在这里插入图片描述

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

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

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

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

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

Let‘s Go!!!😉


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.hqwc.cn/news/454421.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跟着pink老师前端入门教程-day18

3、CSS3 3D转换 生活中的环境是3D的&#xff0c;照片就是3D物体在2D平面呈现的例子 特点&#xff1a;近大远小&#xff0c;物体后面遮挡不可见 3.1 三维坐标系 三维坐标系其实就是指立体空间&#xff0c;立体空间是由3个轴共同组成的 x轴&#xff1a;水平向右 注意&#x…

服务器和云服务器哪个更安全?

随着云计算技术的不断发展&#xff0c;越来越多的企业开始选择使用云服务器来存储和处理数据。然而&#xff0c;对于一些企业来说&#xff0c;他们可能更倾向于使用传统的服务器。在这种情况下&#xff0c;安全性成为了一个重要的考虑因素。那么&#xff0c;服务器和云服务器哪…

JavaWeb之HTML-CSS --黑马笔记

什么是HTML ? 标记语言&#xff1a;由标签构成的语言。 注意&#xff1a;HTML标签都是预定义好的&#xff0c;HTML代码直接在浏览器中运行&#xff0c;HTML标签由浏览器解析。 什么是CSS ? 开发工具 VS Code --安装文档和安装包都在网盘中 链接&#xff1a;https://p…

基础数学问题整理

最近刷了一些关于基础数学问题的题目&#xff0c;大致是关于组合数、分解质因数还有一些思维题&#xff0c;题目来自洛谷的【数学1】基础数学问题 - 题单 - 洛谷&#xff0c;很多思路还是之前没有见过的&#xff0c;都是简单到一般难度的题目&#xff08;橙、题、绿题&#xff…

解读域用户属性值UserPrincipalName

在Active Directory (AD) 环境中&#xff0c;UserPrincipalName&#xff08;UPN&#xff09;属性是一个用于标识域用户的特殊属性&#xff0c;其解读如下&#xff1a; 全称&#xff1a;User Principal Name用途&#xff1a;UserPrincipalName 是一个基于Internet电子邮件地址格…

【视频编码\VVC】变换编码基础知识及标准设计相关参数

变化编码的基础知识 定义&#xff1a;变换编码是将以空间域像素形式描述的图像转换至变换域&#xff0c;以变换系数的形式加以表示。 大部分图像都包含较多平坦区域和内容变化缓慢的区域&#xff0c;使得图像能量在空间域的分散转换为变换域的相对集中分布&#xff0c;从而达…

爬虫实战--爬取简单文字图片并保存到mongodb数据库

文章目录 前言发现宝藏 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚&#xff0c;文章中如果有记录错误&#xff0c;欢迎读者朋友们…

UE中对象创建方法示例和类的理解

对象创建方法示例集 创建Actor示例 //创建一个护甲道具 AProp* armor GetWorld()->SpawnActor<AProp>(pos, rotator); 创建Component示例 UCapsuleComponent* CapsuleComponent CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComponent&qu…

EasyX图形库学习(一、窗口创建函数initgraph、背景颜色设置setbkcolor、图形绘制函数)

目录 一、easyX图形库基本介绍 1、easyX的原理 2、easyX的安装 3、easyX的颜色&#xff08;RGB颜色模型&#xff09; 颜色模型相关函数: 4、easyX的坐标 二、相关函数介绍: 绘图设备相关函数&#xff1a; 图形颜色及样式设置相关函数: 图形绘制相关函数: 文字输出相关…

机器学习基础、数学统计学概念、模型基础技术名词及相关代码个人举例

1.机器学习基础 &#xff08;1&#xff09;机器学习概述 机器学习是一种人工智能&#xff08;AI&#xff09;的分支&#xff0c;通过使用统计学和计算机科学的技术&#xff0c;使计算机能够从数据中学习并自动改进性能&#xff0c;而无需进行明确的编程。它涉及构建和训练机器…

【开源】基于JAVA+Vue+SpringBoot的陕西非物质文化遗产网站

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 设计目标2.2 研究内容2.3 研究方法与过程2.3.1 系统设计2.3.2 查阅文献2.3.3 网站分析2.3.4 网站设计2.3.5 网站实现2.3.6 系统测试与效果分析 三、系统展示四、核心代码4.1 查询民间文学4.2 查询传统音乐4.3 增改传统舞…

蓝桥杯每日一题-----数位dp练习

题目 链接 参考代码 写了两个&#xff0c;一个是很久以前写的&#xff0c;一个是最近刚写的&#xff0c;很久以前写的时候还不会数位dp所以写了比较详细的注释&#xff0c;这两个代码主要是设置了不同的记忆数组&#xff0c;通过这两个代码可以理解记忆数组设置的灵活性。 im…