发布于 2015-06-14 01:59:55 | 140 次阅读 | 评论: 0 | 来源: 网络整理
让已有的运算符也可以对自定义的类和结构进行运算,这称为运算符重载。
这个例子展示了如何用+
让一个自定义的结构做加法。算术运算符+
是一个两目运算符,因为它有两个操作数,而且它必须出现在两个操作数之间。
例子中定义了一个名为Vector2D
的二维坐标向量 (x,y)
的结构,然后定义了让两个Vector2D
的对象相加的运算符函数。
struct Vector2D {
var x = 0.0, y = 0.0
}
@infix func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
该运算符函数定义了一个全局的+
函数,这个函数需要两个Vector2D
类型的参数,返回值也是Vector2D
类型。需要定义和实现一个中置运算的时候,在关键字func
之前写上属性 @infix
就可以了。
在这个代码实现中,参数被命名为了left
和right
,代表+
左边和右边的两个Vector2D
对象。函数返回了一个新的Vector2D
的对象,这个对象的x
和y
分别等于两个参数对象的x
和y
的和。
这个函数是全局的,而不是Vector2D
结构的成员方法,所以任意两个Vector2D
对象都可以使用这个中置运算符。
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// combinedVector 是一个新的Vector2D, 值为 (5.0, 5.0)
这个例子实现两个向量 (3.0,1.0)
和 (2.0,4.0)
相加,得到向量 (5.0,5.0)
的过程。如下图示:
上个例子演示了一个双目中置运算符的自定义实现,同样我们也可以玩标准单目运算符的实现。单目运算符只有一个操作数,在操作数之前就是前置的,如-a
; 在操作数之后就是后置的,如i++
。
实现一个前置或后置运算符时,在定义该运算符的时候于关键字func
之前标注 @prefix
或 @postfix
属性。
@prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
这段代码为Vector2D
类型提供了单目减运算-a
,@prefix
属性表明这是个前置运算符。
对于数值,单目减运算符可以把正数变负数,把负数变正数。对于Vector2D
,单目减运算将其x
和y
都进进行单目减运算。
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// negative 为 (-3.0, -4.0)
let alsoPositive = -negative
// alsoPositive 为 (3.0, 4.0)
组合赋值是其他运算符和赋值运算符一起执行的运算。如+=
把加运算和赋值运算组合成一个操作。实现一个组合赋值符号需要使用@assignment
属性,还需要把运算符的左参数设置成inout
,因为这个参数会在运算符函数内直接修改它的值。
@assignment func += (inout left: Vector2D, right: Vector2D) {
left = left + right
}
因为加法运算在之前定义过了,这里无需重新定义。所以,加赋运算符函数使用已经存在的高级加法运算符函数来执行左值加右值的运算。
var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// original 现在为 (4.0, 6.0)
你可以将 @assignment
属性和 @prefix
或 @postfix
属性起来组合,实现一个Vector2D
的前置运算符。
@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D {
vector += Vector2D(x: 1.0, y: 1.0)
return vector
}
这个前置使用了已经定义好的高级加赋运算,将自己加上一个值为 (1.0,1.0)
的对象然后赋给自己,然后再将自己返回。
var toIncrement = Vector2D(x: 3.0, y: 4.0)
let afterIncrement = ++toIncrement
// toIncrement 现在是 (4.0, 5.0)
// afterIncrement 现在也是 (4.0, 5.0)
注意:
默认的赋值符是不可重载的。只有组合赋值符可以重载。三目条件运算符a?b:c
也是不可重载。
Swift无所知道自定义类型是否相等或不等,因为等于或者不等于由你的代码说了算了。所以自定义的类和结构要使用比较符==
或!=
就需要重载。
定义相等运算符函数跟定义其他中置运算符雷同:
@infix func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
@infix func != (left: Vector2D, right: Vector2D) -> Bool {
return !(left == right)
}
上述代码实现了相等运算符==
来判断两个Vector2D
对象是否有相等的值,相等的概念就是它们有相同的x
值和相同的y
值,我们就用这个逻辑来实现。接着使用==
的结果实现了不相等运算符!=
。
现在我们可以使用这两个运算符来判断两个Vector2D
对象是否相等。
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
println("这两个向量是相等的.")
}
// prints "这两个向量是相等的."