Swift 運算子過載簡介

2021-09-19 08:23:40 字數 4200 閱讀 5435

在任何一門計算機程式語言中,運算子過載都是非常強大的特性之一,因此蘋果決定為 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...