1、简介
Swift中类或结构体可以对已有的运算符进行自定义实现,赋予另外一种功能。可以成为运算符函数,即运算符重载。
2、运算符函数
2.1、双目运算符
下面将通过例子展示自定义结构体如何实现加法运算符(+)和减法运算符(-),加法运算符和减法运算符是双目运算符,可以对两个值进行运算,并且在两个值之间。
例子中定义了一个Coordinate的结构体,包含x和y两个值,表示平面坐标系上面的点。
struct Coordinate {
var x: Double = 0.0
var y: Double = 0.0
}
extension Coordinate {
static func +(lhs: Coordinate, rhs: Coordinate) -> Coordinate {
coordinate = Coordinate(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}
static func -(lhs: Coordinate, rhs: Coordinate) -> Coordinate {
coordinate = Coordinate(x: lhs.x - rhs.x, y: lhs.y - rhs.y)
}
}
上述两个运算符函数被定义为Coordinate的类方法,运算符函数名和重载的运算符保持一致。加法运算符(+)和减法运算符(-)是双目运算符,因此接收两个Coordinate类型的参数,返回一个Coordinate类型的返回值。
上述两个类方法可以在任意两个Coordinate实例之间作为中缀运算符使用:
let point = Coordinate(x: 1.0, y: 1.0)
let anotherPoint = Coordinate(x: 2.0, y: 2.0)
let resultPoint1 = point + anotherPoint
let resultPoint2 = point - anotherPoint
print(resultPoint1)
print(resultPoint2)
这个例子中实现了(1.0,1.0)和(2.0,2.0)两个点的相加和相减,得到两个新的点(3.0,3.0)和(-1.0,-1.0)
Coordinate(x: 3.0, y: 3.0)
Coordinate(x: -1.0, y: -1.0)
2.2、前缀运算符、后缀运算符
2.1节的两个运算符函数实现了双目运算的自定义实现。类和结构体也可以实现单目运算符,单目运算符只运算一个值。运算符出现在值之前为前缀运算符,出现在值之后为后缀运算符。
实现单目运算符需在在声明运算符函数时在func关键字之前添加prefix(前缀)(例如:-a)或postfix(后缀)(例如:b!)修饰符。
extension Coordinate {
static prefix func +(coordinate: Coordinate) -> Coordinate {
return Coordinate(x: +coordinate.x, y: +coordinate.y)
}
static prefix func -(coordinate: Coordinate) -> Coordinate {
return Coordinate(x: -coordinate.x, y: -coordinate.y)
}
}
上述的两个运算符函数为单目运算运算符函数。由于是前缀运算符,需要在
func关键字之前加上prefix修饰符。
上述两个运算符函数只对Coordinate实例的x、y做简单的正负改变:
let point = Coordinate(x: 1.0, y: 1.0)
let anotherPoint = Coordinate(x: 2.0, y: 2.0)
print(-point)
print(+anotherPoint)
这个例子中对(1.0,1.0)和(2.0,2.0)两个点进行正负运算,输出结果为:
Coordinate(x: -1.0, y: -1.0)
Coordinate(x: 2.0, y: 2.0)
2.3、复合赋值运算符
复合赋值运算符是赋值运算符(=)和其他运算符进行结合。例如加法运算符(+)和赋值运算符(=)相结合组成加法赋值运算符(=+)。复合赋值运算符函数需要将左值进行inout关键修饰,因为在函数内部要对左值进行直接的修改。
extension Coordinate {
static func +=(lhs: inout Coordinate, rhs: Coordinate) {
lhs = Coordinate(x: lhs.x + rhs.x, y: lhs.y + rhs.y)
}
static func -=(lhs: inout Coordinate, rhs: Coordinate) {
lhs = Coordinate(x: lhs.x - rhs.y, y: lhs.y - rhs.y)
}
}
上述两个运算符函数实现了加法赋值运算符和减法赋值运算符的自定义。
var point = Coordinate(x: 1.0, y: 1.0)
let anotherPoint = Coordinate(x: 2.0, y: 2.0)
point += anotherPoint
print(point)
由于符合赋值运算符函数的左值进行了inout修饰,运算的结果是对左值进行直接的修改,输入结果为:
Coordinate(x: 3.0, y: 3.0)
注意:不能对默认的赋值运算符(=)进行重载,只有复合赋值运算符可以重载。三目条件运算符(a ? b : c)也不能进行重载。
2.4、等价运算符
自定义类和结构体没有对等价运算符进行默认的实现。等价运算符一般被称为相等运算符(==)和不等运算符(!=)。
对于自定义的类型,Swift无法进行判等运算,因为“相等”的含义取决于自定义类型在代码中扮演的角色。为了使自定义类型能够进行等价运算,我们可以对等价运算符进行自定义实现。
extension Coordinate {
static func ==(lhs: Coordinate, rhs: Coordinate) -> Bool {
if lhs.x == rhs.x && lhs.y == rhs.y {
return true
}
return false
}
static func !=(lhs: Coordinate, rhs: Coordinate) -> Bool {
if lhs.x != rhs.x || lhs.y != rhs.y {
return true
}
return false
}
}
上述的运算符函数实现了“相等”运算符,来判断两个Coordinate类型是否相等,对于Coordinate类型而言,相等表示两个属性“x”和“y”相等;“不等”运算符表示只要Coordinate只要有一个属性不相等,即可判断为两个Coordinate类型不相等。
let point = Coordinate(x: 1.0, y: 1.0)
let anotherPoint = Coordinate(x: 2.0, y: 2.0)
print(point == anotherPoint)
print(point != anotherPoint)
由于point的两个属性x、y和anotherPoint的两个属性x、y值不相等,因此进行相等(==)运算的结果为false,进行不等(!=)的运算结果为true。
2.5、自定义运算符
除了标准运算符,Swift还可以声明和实现自定义运算符。
自定义运算符需要在全局作用域通过关键字operator进行定义,同时要指定prefix(前缀)、infix(中缀)或postfix(后缀)修饰符:
prefix operator +++
上面的代码定义了一个名为+++的前缀运算符。在Swift中+++并没有实际的意义,我们可以通过Coordinate实例来定义它的意义。对于Coordinate类型来讲,可以将+++定义为双自增前缀运算符,实现Coordinate对自身的相加。
extension Coordinate {
static prefix func +++(coordinate: inout Coordinate) -> Coordinate {
coordinate += coordinate
return coordinate
}
}
上述中的运算符函数通过自定义的加法赋值运算符让Coordinate实现自身的相加。
var point = Coordinate(x: 1.0, y: 6.0)
let anotherPoint = +++point
由于+++运算符实现对自身相加,并输出一个Coordinate实例,因此上述例子中point的值最终的结果为(2.0,12.0),anotherPoint的值为(2.0,12.0)。