在任何一門計算機程式語言中,運算子過載都是非常強大的特性之一,因此蘋果決定為 swift 也提供這一機制。然而,"能力越強責任越大"。利用運算子過載你很容易實現一些奇怪的場景,例如用減法運算子實現兩數相加,或者用乘法運算子實現兩數相除,但這顯然都不是你希望出現的。
好了,閒話少敘 —— 讓我們看看運算子過載究竟是怎麼一回事。
這一小節的任務很簡單:擴充套件乘法運算子的標準功能,使其適用於字串。你將會用到字串拼接運算子,想象一下這種用法:
"abc" * 5 = "abc" + "abc" + "abc" + "abc" + "abc" = "abcabcabcabcabc"
正式編碼之前,思考一下應該怎麼做,分幾步來實現。我的做法是這樣的:
演算法大致就是這樣,接下來讓我們付諸實踐。
啟動 xcode 並新建乙個 playground 檔案。刪除原有**,新增乘法運算子的函式原型:
func *(lhs: string, rhs: int) -> string
函式有兩個引數 —— 左運算元是string
型別,右運算元是int
型別,函式返回型別為string
。
函式體內應該完成三件事。首先,定義result
變數並初始化為函式的string
引數 —— 這是乙個變數,稍後會修改它的值。
var result = lhs
接下來使用for in
控制流語句及閉區間執行符從 2 開始迴圈,直到函式的int
引數時為止:
for _ in 2...rhs
迴圈體內只有乙個任務 —— 更新result
:
result += lhs
注意:你也可以按如下方式來寫 —— 上邊這種寫法更短,是因為用了加法復合運算子。
result = result + lhs
最後返回 result:
return result
現在我們直接使用運算子:
let u = "abc"
let v = u * 5
搞定了!只是還有乙個問題 —— 你只能將其用於字串,那其它型別的資料怎麼辦?我們使用范型運算子來完善。
泛型預設是不支援運算子的,所以需要協議來支援。向 playground 中新增協議原型:
protocol type
現在向協議中新增加法復合運算子函式的原型:
func +=(inout lhs: self, rhs: self)
函式擁有左右運算元,並且都設定為self
型別 —— 這是一種巧妙的方式,說明二者的型別都是實現了該協議的類。左運算元標記為inout
,因為它的值是要被修改並且最後被函式返回的。
或者,你也可以定義加法運算子的函式原型:
func +(lhs: self, rhs: self) -> self
函式擁有self
型別的左右運算元,並且加法運算的返回結果也是self
。這種情況下就不需要使用inout
引數了。
接下來,為string
,int
,double
,float
等實現了type
協議的型別建立擴充套件。
extension string: type {}
extension int: type {}
extension double: type {}
extension float: type {}
注意:這些擴充套件的實現是空的,因為你並不打算為預設型別新增任何東西,僅僅是要讓他們遵循type
協議。
現在向 playground 中新增乘法操作符函式原型:
func *(lhs: t, rhs: int) -> t
函式有兩個引數,左運算元是t
型別,右運算元是int
型別,函式返回型別為t
。利用型別約束使t
型別遵循type
協議,這樣它就可以使用加法復合運算子了。
注意:你可以使用where
關鍵字定義型別約束——儘管上邊的方法更簡短:
func *(lhs: t, rhs: int) -> t
函式的實現跟之前一樣:
var result = lhs
for _ in 2...rhs
return result
注意:可以使用加法操作符替代,但要確保它的函式原型新增到了協議中。
測試一下:
let x = "abc"
let y = x * 5
let a = 2
let b = a * 5
let c = 3.14
let d = c * 5
let e: float = 4.56
let f = e * 5
搞定了!不過有乙個問題:你使用的是標準乘法運算子,這個可能造成歧義。如果換成其它運算子會更好。接下來我們試著用自定義運算子解決這個問題。
首先新增下面一行到 playground:
infix operator **
一步一步解釋:
自定義運算子的函式原型與標準運算子類似 —— 只有函式名不同:
func **(lhs: t, rhs: int) -> t
函式實現跟之前完全一樣:
var result = lhs
for _ in 2...rhs
return result
測試一下:
let g = "abc"
let h = g ** 5
let i = 2
let j = i ** 5
let k = 3.14
let l = k ** 5
let m: float = 4.56
let n = m ** 5
搞定了!還有乙個問題——運算子的復合型別還沒有定義,接下來我們解決這個問題:
復合運算子的型別、優先順序和結合性和之前一樣 —— 只有名稱不同:
infix operator **=
接著向 playground 新增復合運算子的函式原型:
func **=(inout lhs: t, rhs: int)
函式沒有返回型別,因為左運算元被標記為inout
。
函式體只做一件事 —— 運用之前的自定義運算子返回乘法結果:
lhs = lhs ** rhs
測試一下:
var o = "abc"
o **= 5
var q = 2
q **= 5
var s = 3.14
s **= 5
var w: float = 4.56
w **= 5
搞定了!這已經是最簡版本了! swift 運算子過載
類和結構體可以位現有的運算子提供自定義的實現。成為運算子過載 code a uikit based playground for presenting user inte ce import uikit struct vector2d extension vector2d let vector ve...
swift 過載運算子
1 自定義乙個 運算子,左邊是string型別,右側為int型別 func left string,right int string let b 10 10 println b 0 3 自定義乙個單項事運算子 postfix func left double string println 0.0 4...
Swift 運算子過載專題
import foundation struct vector3 var va vector3 x 1,y 2,z 3 var vb vector3 x 4,y 5,z 6 func left vector3,right vector3 vector3 va vb func left vector3...