Swift 允許對現有運算符重載,也可自定義新運算符。重載本質是定義全局函數,函數名為運算符符號。
// 系統內置:Int + Int
func +(left: Int, right: Int) -> Int { return left + right }
// 自定義:Int + Double
func +(left: Int, right: Double) -> Double {
return Double(left) + right
}
// 數組追加元素
func +(var left: [T], right: T) -> [T] {
left.append(right)
return left
}
// 注意:Swift 不支持重載賦值運算符 =
++i),需 prefix 關鍵字。i++),需 postfix 關鍵字。prefix func ++(array: inout [T]) -> [T] {
array.append(array.last!)
return array
}
postfix func --(array: inout [T]) -> [T] {
array.removeLast()
return array
}
var arr = ["iOS", "Android", "WP"]
print(++arr) // ["iOS", "Android", "WP", "WP"]
如 +=、-=。第一參數需 inout。
func +=(left: inout [T], right: T) {
left.append(right)
}
var list = ["iOS", "Android"]
list += "WP" // ["iOS", "Android", "WP"]
自定義類型支持比較,需:
Equatable(實現 ==)和 Comparable(實現 <)。== 和 <,Swift 自動合成 !=、<=、>、>=。struct Rect: Equatable, Comparable {
var w: Double, h: Double
static func ==(lhs: Rect, rhs: Rect) -> Bool {
return lhs.w * lhs.h == rhs.w * rhs.h
}
static func <(lhs: Rect, rhs: Rect) -> Bool {
return lhs.w * lhs.h < rhs.w * rhs.h
}
}
let r1 = Rect(w: 5, h: 4) // 面積 20
let r2 = Rect(w: 2, h: 8) // 面積 16
print(r1 < r2) // false
print(r1 > r2) // true (自動合成)
prefix operator 運算符名
infix operator 運算符名 { associativity left/right/none precedence 100 }
postfix operator 運算符名
prefix:單目前綴infix:雙目中綴(最常用)postfix:單目後綴associativity:左結合/右結合/無結合precedence:優先級(默認 100,乘除 150,加減 140)infix operator ** { associativity left precedence 160 } // 優先級高於乘除
func **(base: Int, exponent: Int) -> Int {
var result = 1
for _ in 1...exponent { result *= base }
return result
}
let a = 5, b = 3
print("\(a) 的 \(b) 次方為: \(a ** b)") // 125
表達式:20 + 10 - 5 * 5 ** 2 - 30
若 ** 優先級 160(高於 * 150),則先算 5 ** 2 = 25,再算 5 * 25 = 125。
若 ** 優先級 140(同加減),左結合則 (20+10-5) * 5 ** 2 ... 結果完全不同。
正確設置優先級和結合性,是自定義運算符正確工作的關鍵。
Swift 運算符系統極具擴展性:
inout 修飾可變參數。prefix/postfix。inout。Equatable + Comparable,只實現 == 和 <。infix/prefix/postfix + 結合性 + 優先級,再實現函數。善用運算符重載可編寫極具表達力的 DSL 風格代碼,但濫用會降低可讀性,建議僅在數學、領域建模等場景使用。