iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
0

Generic Types 泛型

在介紹泛型之前,先來講解一下 OOP 三大特性中的 多型

多型是一種操作介面,可以使用同一種方法操作不同的型別資料,透過多型可以提升程式碼的維護性,但是光是多型就有很多種類,廣費的定義就是分為動態多型靜態多型,至於我們今天要聊到的就是屬於靜態多型的一種:參數多型 ( parametric polymorphism ),就是所謂的泛型。

Generic Programming

我們先來看一個例子,假使三種忍者:感知忍者醫療忍者還有影級忍者

enum 感知忍者 {
    case 長門
    case 二代土影
    case 扉間
}

enum 醫療忍者 {
    case 香燐
    case 小櫻
    case 綱手
}

enum 影級忍者 {
    case 水影
    case 風影
    case 火影
    case 土影
    case 雷影
}

然而感知忍者需要出任務,所以定義一個方法叫做感知忍者出任務

func 感知忍者出任務(_ ninja: 感知忍者) {
    print("\(ninja) 出任務!")
}

感知忍者出任務(.長門) // 長門 出任務

但是如果今天另外兩種忍者也要出任務,醫療忍者影級忍者,這時候可能就要再新增兩種方法,所以到最後就會有三種方法:

func 感知忍者出任務(_ 感知忍者: 感知忍者) {
    print("\(感知忍者) 出任務!")
}

func 醫療忍者出任務(_ 醫療忍者: 醫療忍者) {
    print("\(醫療忍者) 出任務!")
}

func 影級忍者出任務(_ 影級忍者: 影級忍者) {
    print("\(影級忍者) 出任務!")
}

感知忍者出任務(.長門) // 長門 出任務!
醫療忍者出任務(.香燐) // 香燐 出任務!
影級忍者出任務(.火影) // 火影 出任務!

這樣每增加一種類型的忍者就要多寫一個方法,到最後就會沒完沒了,而且實際要做的內容都是一樣的,所以最好的方式就是希望能透過同一種方法,針對不同型別的資料做相同的處理,這種概念就是 Gerneric Programming

Generic Programming 就是把原本在 Design Time 應該要決定的參數型別,挪到 Compile Time 再來分析判斷,但是這樣講還是有點模糊對吧,我們直接來看例子,把上面的範例改寫一下:

func 忍者出任務<忍者>(_ 忍者: 忍者) {
    print("\(忍者) 出任務!")
}

忍者出任務(感知忍者.長門)
忍者出任務(醫療忍者.香燐)
忍者出任務(影級忍者.火影)

透過 忍者出任務(_ 忍者) 針對不同型別的參數,進行相同操作,這樣就把原本三個不同的方法,統一成一種了,但是,這是什麼語法?

func 方法名稱<T>(參數: T) {
	...
}

這就是具有 Generic 的 Parameter,在 Design Time 時,透過<> 來定義泛型參數,然而 T 是一個自定義的參數名稱,Swift 創造一個 Type 給我們作為暫時性的型別,然而這個型別可以接受外部傳入的任何型別的資料,等到編譯的時候就會依照會不傳入的資料型別,把 T 全部轉換為該型別。

所以回來看上面的範例,我們透過 <忍者> 作為一個 Generic Type,並且定義一個參數 忍者 並標記 Generic Type,所以在呼叫的時候,同樣是呼叫 忍者出任務,但是因為傳入的參數分別是不同的型別,他就會依照這個型別來去做轉換,把 忍者 這個 Generic Type 替換掉。

泛型參數的型別約束

假使今天有個 isEqual() 用來比較兩數是否相等,我們也許可以這樣寫:

func isEqual<Data>(x: Data, y: Data) -> Bool {
    x == y
}

看似沒什麼問題,但是錯誤隨之而來的出現:Binary operator '==' cannot be applied to two 'Data' operands,這段錯誤就是跟你說你不能用 == 來比較兩個 Data 型別的資料,那為什麼會有這個錯誤?

一般我們使用的基本型別,像是 Int、Float 或是 Double,其實都遵循了 Equatable 協定,然而如果我們要使用 == 運算子來比較數值,資料型別就必須遵循 Equatable 協定,所以我們可以在 Generic Type 後方來遵循 Protocol,來進行型別約束:

func isEqual<Data: Equatable>(_ x: Data, _ y: Data) -> Bool {
    x == y
}

isEqual(10, 10) // true
isEqual("老虎", "老鼠") // false

上一篇
Day 28 | Swift Error Handling
下一篇
Day 30 | 鐵人賽終章:心得
系列文
給我 30 天,給你一輩子:Swift 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言