Swift 运算符的重载和自定义

1. 运算符的重载

1.1 基本运算符的重载

1
2
3
4
5
6
7
8
9
10
11
func * (lhs: String, rhs: Int) -> String {
var result = lhs
for _ in 1..<rhs {
result += lhs
}
return result
}

let t = "abc"
print(t * 3)
// print "abcabcabc"

如上所示,我们重载了运算符 * 。再看看另一个例子:

1
2
3
struct Vector2D {
var x = 0.0, y = 0.0
}

我们定义了如上的结构体,如果想把两个 Vector2D 类型的实例相加,编译器是会报错的。如果我们重载操作符 + ,就可以实现相加:

1
2
3
4
5
6
7
func + (lhs: Vector2D, rhs: Vector2D) -> Vector2D {
return Vector2D(x: lhs.x + lhs.x, y: rhs.y + rhs.y)
}
let first = Vector2D(x: 1.0, y: 2.0)
let second = Vector2D(x: 3.0, y: 4.0)
print(first + second)
// print "Vector2D(x: 4.0, y: 6.0)"

1.2 泛型运算符

1
2
3
4
5
6
7
func * <T> (lhs: T, rhs: Int) -> T {
var result = lhs
for _ in 1..<rhs {
result += lhs
}
return result
}

按照常理,我们会将第一个例子做如上改写,但是编译器会提示 Binary operator ‘+=’ cannot be applied to two ‘T’ operands ,这是因为 T 类型并不能直接使用加法符合运算符,我们可以通过让 T 类型遵循实现了加法功能的协议来解决这个问题,改写后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protocol Type {
static func + (lhs: Self, rhs: Self) -> Self
static func += (lhs: inout Self, rhs: Self)
}

extension String: Type {}
extension Int: Type {}
extension CGFloat: Type {}

func * <T: Type> (lhs: T, rhs: Int) -> T {
var result = lhs
for _ in 1..<rhs {
// result = result + lhs
result += lhs
}
return result
}

2. 运算符的自定义

先介绍 Swift 中的三个关键字:

  • prefix:前缀运算符,比如 ++i 中的 ++
  • postfix:后缀运算符,比如 i++ 中的 ++
  • infix:中缀运算符,比如 a + b 中的 +

这里仅以 infix 为例示范其用法,现在我们自定义一个运算符 ** 和符合运算符 **= ,实现第一个例子的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
infix operator **
func ** <T: Type> (lhs: T, rhs: Int) -> T {
var result = lhs
for _ in 1..<rhs {
result += lhs
}
return result
}

infix operator **=
func **= <T: Type> (lhs: inout T, rhs: Int) {
lhs = lhs ** rhs
}

let t = "abc"
let s = t ** 3
print(s)
// print "abcabcabc"
var u = "abc"
u **= 3
print(u)
// print "abcabcabc"

至此,运算符的重载和自定义的基本功能就介绍完毕了。当然,自定义运算符同样是可以定义优先级和结合性的,这里不做过多讲解,有兴趣的朋友可以自行查阅资料。

您的支持将鼓励我继续创作!
0%