在写 Swift 代码时,有时候会遇到这样的场景:你定义了一个表示二维坐标的结构体,想把两个点相加得到一个新的点。按常规做法,你可能会写一个 add(_ other: Point) 方法。但要是能直接用 + 号是不是更顺?这其实就是运算符重载的用武之地。
什么是运算符重载
Swift 允许我们为自定义类型赋予标准运算符(比如 +、-、==)新的行为。这个过程就叫运算符重载。它不会改变原有运算符对 Int 或 String 的作用,只是给你的类或结构体也加上类似原生类型的操作体验。
从一个例子开始
假设我们有一个表示复数的结构体:
struct Complex {
var real: Double
var imaginary: Double
}
现在想实现两个复数相加。数学上,(a + bi) + (c + di) = (a+c) + (b+d)i。我们可以这样重载 + 运算符:
static func + (left: Complex, right: Complex) -> Complex {
return Complex(real: left.real + right.real,
imaginary: left.imaginary + right.imaginary)
}
之后就能这么用了:
let c1 = Complex(real: 2.0, imaginary: 3.0)
let c2 = Complex(real: 1.0, imaginary: 4.0)
let result = c1 + c2 // 得到 (3.0, 7.0)
重载等于运算符
如果你希望两个复数在实部和虚部都相等时被视为相同,可以重载 ==:
static func == (left: Complex, right: Complex) -> Bool {
return left.real == right.real && left.imaginary == right.imaginary
}
这样一来,就可以直接用 if c1 == c2 判断相等性,和其他类型一样自然。
自定义中缀运算符
除了系统已有的,Swift 还支持定义新运算符。比如你想用 +++ 表示两个复数的实部相加但虚部取最大值:
infix operator +++
static func +++ (left: Complex, right: Complex) -> Complex {
return Complex(real: left.real + right.real,
imaginary: max(left.imaginary, right.imaginary))
}
虽然这个操作不常见,但在特定业务场景下,比如数据合并时保留最强信号,这种表达会很直观。
注意别滥用
运算符重载能让代码简洁,但也容易被人滥用。比如用 - 来拼接字符串就不合适,违背了大家的认知习惯。建议只在逻辑清晰、符合直觉的时候使用,别为了炫技而增加理解成本。
另一个坑是优先级。自定义运算符如果不指定优先级组,可能在复杂表达式里出错。Swift 提供了像 AdditionPrecedence、MultiplicationPrecedence 这样的分组,定义新运算符时可以指定。
实际应用场景
在开发图表应用时,你可能会有 Point、Size、Rect 这些结构体。通过重载 + 和 -,可以让坐标偏移的计算变得更直观:
let position = Point(x: 10, y: 20)
let offset = Size(width: 5, height: 5)
let newPosition = position + offset // 自然得像说话
这种写法读起来接近日常语言,团队协作时也更容易理解。