Swift運算符函數
運算符函數
讓已有的運算符也可以對自定義的類和結構進行運算,這稱為運算符重載。
這個例子展示了如何用+
讓一個自定義的結構做加法。算術運算符+
是一個兩目運算符,因為它有兩個操作數,而且它必須出現在兩個操作數之間。
例子中定義了一個名為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 "這兩個向量是相等的."