一、重载运算符给函数“加戏”,我先带你跑通第一个 demo

我带过的新手学员,十有八九都被“重载”这个词唬住过。

重载说白了就是同一个函数名,干不同的事

你先看这段能直接跑的代码:

// 运行环境:Swift 5.0+,Xcode 14+
// 函数重载最简版:两个同名函数,参数类型不同
// 整数加法
func addFunc(_ a: Int, _ b: Int) -> Int {
return a + b
}
// 浮点数加法(同名函数)
func addFunc(_ a: Double, _ b: Double) -> Double {
return a + b
}
// 调用
let intResult = addFunc(10, 20)      // 30
let doubleResult = addFunc(3.5, 2.5) // 6.0
print("整型结果:(intResult),浮点型结果:(doubleResult)")

学员最常踩的坑是:以为重载就是改返回值类型

错!

Swift 编译器所关注的是具有特定类型的参数,以及参数的数量多少,还有参数所带有的标签,返回值不一样的情况并不被算作重载

Swift 函数参数语法 _Swift 运算符重载 _ 自定义运算符实现

在下述代码当中,某一个参数属于 Int 类型,而另外一个乃是 Double 类型,如此这般编译器方可明确知晓该调用哪一个

二、运算符重载就是“给+号加新功能”,直接上 Circle 类实战

自定义运算符实现 _Swift 运算符重载 _Swift 函数参数语法

你每日都在使用的那个+号,实际上也是经过重载而得来的,它能够对整数进行加法运算,能够对浮点数进行加法运算,并且还能够拼接字符串

下面我们让+号能加圆形

Swift 函数参数语法 _Swift 运算符重载 _ 自定义运算符实现

// 圆形类:半径 + 圆心
class Circle {
var radius: Double
var centerX: Double
var centerY: Double
init(radius: Double, centerX: Double, centerY: Double) {
self.radius = radius
self.centerX = centerX
self.centerY = centerY
}
}
// 重载 + 运算符:半径相加,圆心取第一个圆
func + (left: Circle, right: Circle) -> Circle {
let newRadius = left.radius + right.radius
return Circle(radius: newRadius,
centerX: left.centerX,
centerY: left.centerY)
}
// 测试
let circle1 = Circle(radius: 5, centerX: 0, centerY: 0)
let circle2 = Circle(radius: 3, centerX: 10, centerY: 10)
let resultCircle = circle1 + circle2
print("新圆半径:(resultCircle.radius)") // 8.0

我带着学员踩过的真切存在的坑,有个学员在进行+号重载操作的时候,把处理边界条件这件事给忘掉了 —— 两个呈现 nil 状态的对象相加,直接就崩溃了。

正确做法要加guard判断。

企业级优化版应该这样写:

// 企业版:支持可选类型 + 异常处理
func + (left: Circle?, right: Circle?) -> Circle? {
guard let left = left, let right = right else {
print("警告:存在 nil 对象,返回 nil")
return nil
}
let newRadius = left.radius + right.radius
return Circle(radius: newRadius,
centerX: left.centerX,
centerY: left.centerY)
}

Swift 运算符重载 _ 自定义运算符实现 _Swift 函数参数语法

三、自定义运算符:手搓一个“++”,分三步走

Swift 移除++后,我们可以自己加回来。

自定义运算符分三步:声明→类型→实现。

// 第一步:声明自定义运算符
prefix operator ++
// 第二步+第三步:实现前缀++(先自加后返回)
prefix func ++ (value: inout Int) -> Int {
value += 1
return value
}
// 测试
var num = 10
let newNum = ++num
print("num: (num), newNum: (newNum)") // num: 11, newNum: 11

自定义运算符实现 _Swift 函数参数语法 _Swift 运算符重载

中缀运算符(两个操作数)写法不同,不需要写prefix

// 自定义中缀运算符:求两个数的平均值
infix operator ±±
func ±± (left: Double, right: Double) -> Double {
return (left + right) / 2
}
let avg = 10.0 ±± 20.0
print("平均值:(avg)") // 15.0

func myFunc(closure:(Circle,Circle)->Circle) {
}
//将重载的加法运算符传入
myFunc(closure: +)

存在这样一种学员常常会踩到的坑,那就是在进行自定义运算符操作的时候,使用了 Swift 所保留的字符,像那些以问号、感叹号开头的字符,一旦这样做,编译的时候就会直接出现报错的情况。

此外存在个隐蔽的坑,前缀运算符以及后缀运算符的参数必定得是 inout,不然的话就无法改变原来的值

四、运算符类型怎么选?

自定义运算符实现 _Swift 运算符重载 _Swift 函数参数语法

一张表帮你避坑

运算符类型 关键字 参数个数 示例
前缀 prefix 1 个 ++a
中缀 infix 2 个 a + b
后缀 postfix 1 个 a++

选型得出这样的结论,在百分之九十的场景当中,会使用中缀运算符,像是自定义向量加法、矩阵乘法这种情形。

前缀/后缀主要用于自增自减、逻辑取反。

我曾带过的学员,老是想着运用后缀运算符去开展复杂的计算,然而呢,结果是参数根本没办法去传递第二个值,最终啊,全都白忙活一场了。

自定义运算符实现 _Swift 运算符重载 _Swift 函数参数语法

记住:后缀只有一个操作数,想传两个参数必须用中缀。

五、最后给你一个排错清单

你在写重载或自定义运算符时,遇到报错按这个顺序查:

1. 运算符声明了吗(prefix operator ++这种)

2. 参数类型匹配吗(重载靠参数区分,不是靠返回值)

3. 中缀/前缀/后缀关键字写对了吗

4. 用了保留字符开头吗(?!=单独不能用)

5. 修改原值加inout了吗

拿上面每一段代码,复制之后放入 Playground 里面,随后运行一回,再去更改更改参数,尝试尝试,半小时的时间就能够彻彻底底搞明白。

课后所进行的练习:自行去定义一种运算符的重载,该运算符要能使得 Circle 与 Int 相乘之后返回的结果是半径被扩大了 N 倍的圆。